[fpc-pascal] Currency constant wrongly stored in generated EXE?

LacaK lacak at zoznam.sk
Wed May 14 13:08:37 CEST 2014


> Lets restate the hole thing, considering unit ncon.pas and pexpr.pas 
> units in FPC 2.6.4
> compiler.
>
> 1° It is not possible, without using some ad hoc adjustements, to have
> always an EXACT CURRENCY stored in a DOUBLE or EXTENDED because Double or
> Extended being expressed as Sign*2^exp*Base2(n). Just start with 0.1 
> to see
> what I mean.
Yes I understand it

>
> 2° trealconstnode class stores the currency_literal value to value_real
> (type bestreal) then converts it to value_currency either in the
> trealconstnode.create or sets it in pexpr.pas  function
> factor(getaddr,typeonly:boolean) : tnode; just after {$ifdef
> FPC_HAS_STR_CURRENCY}
>
> 3° c:=92233720368547; // The original problem
> multiple operations involve *10000 (OK per see) and /10000 (not so good)
> while parsing the constant to bestreal type before generating .EXE code.
> (bestreal is Extended on Intel I386 and Up and Double on ARM).
>
> 4° The compiler will not compain about Currency_Value:=0.99999 whereas 
> the
> max decimal precision is 0.9999 for decimal part.
>
> 5° What I found is that only + or - operations on Currency's giving a
> Currency will be generated with plain Int64 addition and subtractions.
>
> Now what ?
>
> It would be interesting that someone who has an ARM based 
> machine/compiler do
> some testing.
>
> Since currency is a very good type for accounting, you know
> Sum(Assets)-Sum(Liabilities)=Sum(Incomes)-Sum(Costs) -> hopefully 
> benefit and exact,
> some workarounds must be found.
> A basic way to circumvent the risks when absolutly necessary would be 
> something like what is decribed next, not very Pascal clean I must 
> admit :
>
> - Insure that the compiler will not see a literal currency when 
> assigning or
> calculating  a precise value containing a literal currency value.
>
> so short example, look at the ASM code generated.
>
> var
> c: currency;
> lInt64:Int64 absolute c; // Avoid use of Currency
> begin
>  c:=0.99999; // Accepted by the compiler ... and rounded to 1
>  c:=0.99986; // Accepted by the compiler ... and rounded to 0.9999
>  c:=0.99984; // Accepted by the compiler ... and rounded to 0.9998
>  { The easy way but uses the FPU }
>  c:=92233720368547; // <- that might be wrongly evaluated by the 
> Compiler (FPU usage) but nothing will be visible in the generated ASM 
> regarding FPU evaluation, except in your case, an invalid HEX value
>  c:=c+0.01; // <- uses FPU
>  writeln('c+0.01 with FPU=', c);
>  { Clumsy but no FPU usage while compiling and executing }
>  lInt64:=922337203685470000; // <- You can test but my bet is that it 
> probably always correctly evaluated by the compiler
>  lInt64:=lInt64+100; // Equivalent to c:=c+0.01
>  writeln('c+0.01 indirect no FPU=', c);
>  readln;
> end;
>
> Your subject has been interesting and I'll be careful now with 
> rounding and Currency.
>
:-) Thanks Bruno for your detailed insight

For now I lost patience and have reinstalled Win98 on same computer 
(same CPU)
I have again reinstalled Lazarus 1.2.2 + FPC 2.6.4
And recompile test application again.
Now are results correct !!!

So culprit was not OS nor CPU but something else has to be wrong.
I will carefully install other applications and check if problem will 
again appears.
For now I have no idea what has confused FPC to generate wrong binary 
representation of mentioned currency value.

-Laco.




More information about the fpc-pascal mailing list