[fpc-pascal] Loss of precision when using math.Max()
C Western
l at c-m-w.me.uk
Sun Jul 1 10:27:33 CEST 2018
On 29/06/18 21:55, Sven Barth via fpc-pascal wrote:
> Am 29.06.2018 um 18:45 schrieb Alan Krause:
>> I stumbled upon something the other day that was causing numerical
>> differences between compiled Delphi and FPC code. Executing the
>> following sample console application illustrates the issue clearly:
>>
>> program test;
>>
>> uses
>> math, SysUtils;
>>
>> var
>> arg1 : double;
>> arg2 : double;
>> res : double;
>> begin
>> arg1 := 100000.00;
>> arg2 := 72500.51;
>> writeln( 'arg1 = ' + FormatFloat( '0.00000000', arg1 ) );
>> writeln( 'arg2 = ' + FormatFloat( '0.00000000', arg2 ) );
>>
>> res := arg1 - arg2;
>> writeln( 'arg1 - arg2 = ' + FormatFloat( '0.00000000', res ) );
>> writeln( 'Max( arg1 - arg2, 0 ) = ' + FormatFloat( '0.00000000',
>> Max( res, 0 ) ) );
>> writeln( 'Max( arg1 - arg2, 0.0 ) = ' + FormatFloat( '0.00000000',
>> Max( res, 0.0 ) ) );
>> end.
>>
>> --- begin output (Linux x86_64) ---
>>
>> arg1 = 100000.00000000
>> arg2 = 72500.51000000
>> arg1 - arg2 = 27499.49000000
>> *Max( res, 0 ) = 27499.49023438*
>> Max( res, 0.0 ) = 27499.49000000
>>
>> --- end output ---
>>
>> I am guessing that the integer value of zero is causing the wrong
>> overloaded function to be called? I was able to solve the problem in
>> my code by replacing the 0 with 0.0.
>
> The compiler converts the 0 to the type with the lowest precision that
> can hold the value (or the largest if none can hold it exactly). For 0
> this is already satisfied by Single, so the compiler essentially has the
> parameter types Double and Single. For some reason (I don't know whether
> it's due to a bug or by design) it picks the Single overload instead of
> the Double one.
> Someone who knows more about the compiler's overload handling would need
> to answer why it favors (Single, Single) over (Double, Double) for
> (Double, Single) parameters (or (Single, Double), the order doesn't
> matter here).
>
> Regards,
> Sven
>
More confusingly, if a single variable is used, the expected Max(Double,
Double) is called:
function Max(a, b: Double): Double; overload;
begin
WriteLn('Double');
if a > b then Result := a else Result := b;
end;
function Max(a, b: Single): Single; overload;
begin
WriteLn('Single');
if a > b then Result := a else Result := b;
end;
var
v1: Double;
v2: Single;
begin
v1 := Pi;
v2 := 0;
WriteLn(v1);
WriteLn(Max(v1,0));
WriteLn(Max(v1,0.0));
WriteLn(Max(v1,v2));
end.
Prints:
3.1415926535897931E+000
Single
3.141592741E+00
Double
3.1415926535897931E+000
Double
3.1415926535897931E+000
If this is not a bug, it would be very helpful if the compiler could
print a warning whenever a value is implicitly converted from double to
single.
Colin
More information about the fpc-pascal
mailing list