[fpc-pascal] Loss of precision when using math.Max()

Florian Klämpfl florian at freepascal.org
Tue Jul 3 20:12:33 CEST 2018


Am 03.07.2018 um 19:42 schrieb gtt at wolfgang-ehrhardt.de:
> 
> Zitat von Vojtěch Čihák <vojtech.cihak at atlas.cz>:
>> will not give any warning even if correct result is 2.5.
>> It is simply absurd because it is not about shooting your own foot. Compiler is not a crystal ball, it does what you 
>> tell him.
>> If you need floating point, use floating point types and floating point division (my example) and if you need signed 
>> results, use
> 
> Really?
> 
> There are other source of loss of precision (in the trunk version) and the compiler does
> not what I tell him. Example:
> 
> const
>    d1: double = 1.0/3.0;
>    d2: double = 1/3;
>    x1: extended = 1.0/3.0;
>    x2: extended = 1/3;
>    s1: single   = 1.0/3.0;
>    s2: single   = 1/3;
> begin
>    writeln(s1:30:10,  s2:30:10);
>    writeln(d1:30:16,  d2:30:16);
>    writeln(x1:30:16,  x2:30:16);
> end.
> 
> and the result
> 
>                    0.3333333433                  0.3333333433
>              0.3333333432674408            0.3333333333333333
>              0.3333333432674408            0.3333333333333333
> 
> The single result is expected. But the  double and extended constants d1, x1 are
> evaluated as single, even if I told the compiler to use the floating point quotient 1.0/3.0.

In pascal, the rule applies that *the resulting type of an operation does not depend on the type a value is assigned 
too*. So: 1.0 fits perfectly into a single, 3.0 as well, they are single constants (you didn't tell the compiler 
otherwise). Nobody wants that unnecessarily larger types are used. So for the compiler this is a single division and 
later on the result is converted into extended. The result for integer is indeed a little bit strange, here probably the 
default rule applies that any /-operand is converted to the best available real type if it is not a real type, thus the 
result differs. Question is, if the compiler should look the operand types and choose more carefully the types, but I 
tend more to say no.

> 
> If I use the integer quotient the values are as expected. This is against intuition 

True, but intuition is bad in programming :)

> and gives
> no warning. And even if I can adapt to this and live with this quirk: 

What is exactly the quirk?

> Is there a definite
> statement, that is will remain so. 

Insert type casts for the constants to get proper results on all archs, see below.

> (Delphi works as expected).

The reason why delphi behaves different is probably due to it's roots in being x87 only: x87 does all calculations with 
extended precision. You get similar trouble if you do multiple single operations in one statement and on x87, the result 
is normally different from all other FPUs because x87 does not round in between. This is different from most other FPU 
implementations. This can be fixed only with the price doing on all non-x87 FPUs floating point operations unnecessarily 
precise.



More information about the fpc-pascal mailing list