### Bookstore

 Computer Math and Games in Pascal (preview) Lazarus Handbook (preview only)

### Author Topic: VarToStr raise RunError(201); Lazarus 1.8.4, Win32  (Read 2612 times)

#### dmitryb

• New Member
• Posts: 35
##### VarToStr raise RunError(201); Lazarus 1.8.4, Win32
« on: May 26, 2018, 05:21:06 pm »
Hi All.

Next code

Code: Pascal  [Select]
1. procedure TfrMainGrid.Button1Click(Sender: TObject);
2. var
3.   bcdVar: Variant;
4.   s: String;
5. begin
6.   VarFmtBCDCreate(bcdVar, VarToBCD(224518.0639999999994919));
7.   bcdVar := bcdVar / 6615;
8.   s := VarToStr(bcdVar); //RunError(201)
9. end;

raise RunError(201);

Lazarus 1.8.4, Win32

I can't understand why.

#### ASerge

• Hero Member
• Posts: 1433
##### Re: VarToStr raise RunError(201); Lazarus 1.8.4, Win32
« Reply #1 on: May 26, 2018, 09:11:48 pm »
Code: Pascal  [Select]
1. {\$MODE OBJFPC}
2. {\$LONGSTRINGS ON}
3. {\$APPTYPE CONSOLE}
4. program Project1;
5.
6. uses fmtBCD, Variants;
7.
8. var
9.   bcdVar: Variant;
10.   S: string;
11. begin
12.   VarFmtBCDCreate(bcdVar, VarToBCD(224518.0639999999994919));
13.   bcdVar := bcdVar;
14.   S := VarToStr(bcdVar);
15.   Writeln(S);
17. end.
Both 32 and 64 bit windows programs display 224518.06400000001. Lazarus 1.8.4.

• Hero Member
• Posts: 9449
##### Re: VarToStr raise RunError(201); Lazarus 1.8.4, Win32
« Reply #2 on: May 26, 2018, 09:48:34 pm »
Which is well within the range +/- of variants.
Variants are not there for precision. They are a convenient but slow and less precise means of communicating to script-like code.
Try to avoid them in normal Pascal. I wish variants did not exist at all.
They are there for Delphi/COM compatibility and therefor targets VB programmers that did not upgrade their knowledge.

If I see a variant used without a good reason the programmer was usually fired or lost his bonus. (yes, I did that, but that was a really incurable case)
« Last Edit: May 26, 2018, 10:01:21 pm by Thaddy »
also related to equus asinus.

#### jamie

• Hero Member
• Posts: 2264
##### Re: VarToStr raise RunError(201); Lazarus 1.8.4, Win32
« Reply #3 on: May 26, 2018, 10:53:33 pm »
This problem has nothing to do with the use of variants..

I use variants a lot especially in windows programming along with the Olevariant etc..

The problem at hand is there is a serious bug in the  fmtBCB file …

Looking at the code I would say a good chunk of it needs to be rewritten.

it does not matter if you call via Variant or call their procedures directly, the divider comes out to the same
errors.

If you take the posters example and change the  / 6615 to something like 10, 1000, 2000 etc it works..

it is having issues doing the math...

with the massive amount of code I see in there just to process BCD digits, I wouldn't even use it.. that is my
personal opinion...

Number 1 at blue screen app creations!

• Hero Member
• Posts: 9449
##### Re: VarToStr raise RunError(201); Lazarus 1.8.4, Win32
« Reply #4 on: May 27, 2018, 09:37:47 am »
A BCD is there to maintain a guaranteed precision over a fixed range. Converting to/from variants will loose that precision. The BCD type as such has no bug that I know of, it is the conversion to/from variant to/from a real type that causes the imprecision. You can not capture a BCD type into a variant and expect the precision to be maintained. That is to be expected since it needs conversion to/from real to be expressed as a variant type internally. BCD is not an OleVariant type, btw....
If you need BCD keep it BCD.
As I wrote, the differing values are explained by these conversions and well within range. That is the danger of using a variant: they are not suitable for BCD without loosing the BCD precision. That is not solvable because of the nature of variants.
I use variants too, for OLE/COM it is warranted or even the only option, but not for BCD types. BCD types are fast and precise over its range as long as all processing is done on its proper type..
Variants are slow and in normal programming a sign of laziness or sheer stupidity. Usually you don't need them.
also related to equus asinus.

#### jamie

• Hero Member
• Posts: 2264
##### Re: VarToStr raise RunError(201); Lazarus 1.8.4, Win32
« Reply #5 on: May 27, 2018, 05:57:48 pm »
I guess you didn't get what I was trying to convey..

if you use the fmtBCD procedures directly, BCDdivide for example the error is still there.

It's not Variant related, the transaction to and from BCD-Variant is working fine, it's the supported
BCD functions/Procedures, mainly the BCDdivide in this case where the issue is..

I wrote a BCD class once for a project but never thought of actually putting it in for public use, it supports
all of the common math operations but I took a little different approach to it that makes it much simpler to

I'll have to dig it out of one my old Delphi projects...

Number 1 at blue screen app creations!

• Hero Member
• Posts: 9449
##### Re: VarToStr raise RunError(201); Lazarus 1.8.4, Win32
« Reply #6 on: May 27, 2018, 06:07:14 pm »
Jamie, BCD and variants don't go together. THAT's the cause.
also related to equus asinus.

#### jamie

• Hero Member
• Posts: 2264
##### Re: VarToStr raise RunError(201); Lazarus 1.8.4, Win32
« Reply #7 on: May 27, 2018, 08:47:45 pm »

The fmtBCD unit has all of the procedures to handle this type directly, the BCDDivide procedure has no
relationship with Variants, only TBCD which is just a record.

if you directly setup a variable of TBCD, set its value using only fmtBCD functions/procedures, NO VARIANT code at all.

and then use the BCDDivide, the same EXACT ERROR appears.

If you can't understand this, and want to keep on insisting its all about variants when it's not, then I guess this is

Number 1 at blue screen app creations!

#### Bart

• Hero Member
• Posts: 3602
##### Re: VarToStr raise RunError(201); Lazarus 1.8.4, Win32
« Reply #8 on: May 27, 2018, 09:02:06 pm »
@jamie: can you please provide an example (without variants) that crashes?
We then could test with trunk and as on fpc-devel wether this is a bug (it sounds like it though).

Bart

#### jamie

• Hero Member
• Posts: 2264
##### Re: VarToStr raise RunError(201); Lazarus 1.8.4, Win32
« Reply #9 on: May 27, 2018, 10:16:36 pm »
Code: Pascal  [Select]
1. procedure TForm1.Button1Click(Sender: TObject);
2. var
3.   B,D,R:TBCD;
4.   S:String;
5. begin
6.   R := StrToBCD('0.0'); //Just to make sure.
7.   B := StrToBCD('224518.0639999999994919');
8.   D := StrToBCD('54');//< test number;
9.   BCDDivide(B,D,R);
10.   //failed numbers I've found so far.
11.   //6615(original),26,27,28, 37,38, 41,42, 51,52,53,54
12.   S := BCDtoStr(R);
13.   Caption := S;
14. end;
15.

I left a failing number in the test but if you experiment with numbers between the for example 43..50 they work as
do many others I found, I don't see a correlation of the values at the moment but...

The fault points to unpack_bcd  generating a range error (201) while in the BCDDivide, I didn't see this for other
operators like -,+ etc..

Number 1 at blue screen app creations!

#### Bart

• Hero Member
• Posts: 3602
##### Re: VarToStr raise RunError(201); Lazarus 1.8.4, Win32
« Reply #10 on: May 27, 2018, 10:49:23 pm »
Confirmed (3.0.4 and trunk).

Bart

#### Bart

• Hero Member
• Posts: 3602
##### Re: VarToStr raise RunError(201); Lazarus 1.8.4, Win32
« Reply #11 on: May 27, 2018, 10:57:24 pm »
Reported as issue #33795, with slightly adapted test program.

Bart

#### engkin

• Hero Member
• Posts: 2513
##### Re: VarToStr raise RunError(201); Lazarus 1.8.4, Win32
« Reply #12 on: May 27, 2018, 11:32:21 pm »
Caused by:
Code: Pascal  [Select]
1.   procedure unpack_BCD ( const BCD : tBCD;
2.                            var bh : tBCD_helper );
3.
4.     var
5.       i : {\$ifopt r+} __lo_bh + 1 ..__hi_bh {\$else} Integer {\$endif};
6.       j : {\$ifopt r+} -1..__high_fraction {\$else} Integer {\$endif};
7.       vv : {\$ifopt r+} \$00..\$99 {\$else} Integer {\$endif};

should be:
Code: Pascal  [Select]
1.   procedure unpack_BCD ( const BCD : tBCD;
2.                            var bh : tBCD_helper );
3.
4.     var
5.       i : {\$ifopt r+} __lo_bh + 1 ..__hi_bh {\$else} Integer {\$endif};
6.       j : {\$ifopt r+} -1..__hi_bh {\$else} Integer {\$endif};
7.       vv : {\$ifopt r+} \$00..\$99 {\$else} Integer {\$endif};

#### jamie

• Hero Member
• Posts: 2264
##### Re: VarToStr raise RunError(201); Lazarus 1.8.4, Win32
« Reply #13 on: May 28, 2018, 05:02:19 am »
Very interesting find..

But I did some testing and the Range definitions differ from my Old Delphi..

For example

fpc
Var
Test :
0..127; = shortInt; // one byte;

0..200 ;= byte;
0..10000; = smallint;
0..65534; = WORD;

and so on..

With my old D3.. They are all Integers! I can see this causing issues if someone wasn't aware of this and casting over?

is it possible this changed at some time or has it always been this way with fpc ?

« Last Edit: May 28, 2018, 05:10:56 am by jamie »
Number 1 at blue screen app creations!

#### WooBean

• Jr. Member
• Posts: 89
##### Re: VarToStr raise RunError(201); Lazarus 1.8.4, Win32
« Reply #14 on: May 28, 2018, 06:28:30 am »
Very interesting find..

But I did some testing and the Range definitions differ from my Old Delphi..

For example

fpc
Var
Test :
0..127; = shortInt; // one byte;

0..200 ;= byte;
0..10000; = smallint;
0..65534; = WORD;

and so on..

With my old D3.. They are all Integers! I can see this causing issues if someone wasn't aware of this and casting over?

is it possible this changed at some time or has it always been this way with fpc ?

We can force an enum size to 4 bytes by using compiler directive {\$Z4} - see https://www.freepascal.org/docs-html/prog/progsu59.html#x66-650001.2.59.

WooBean
Win7/64, Lazarus 1.8 win64-win64, FPC 3.0.4