Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unexpected result from Max function in FreePascal

The running example is really simple to understand:

program Project1;

uses
SysUtils, Math;

var
  fValue: double;
  fValueMax: double;
begin
  fValue := 7.0207503445953527;
  fValueMax := Max(0, fValue);
  writeln(fValue);
  writeln(fValueMax);
  readln;
end.   

However the result is completely unexpected. For some reason, the Max function does not only return the larger number from the two arguments but also changes it's value.

In the example code above, the expected value of fValueMax is exactly fValue, but instead fValueMax is bigger. The difference is approximately E-7, so small, but still unexpected and crashes my following code (which is not published here to keep the question clear and simple).

like image 454
skrat Avatar asked Feb 23 '26 08:02

skrat


1 Answers

I should state upfront that the last time I used Pascal was close to 25 years ago. But I pulled down Free Pascal out of curiosity and tried this:

program Project1;

uses
SysUtils, Math;

var
  fValue: double;
  fValueMax: double;

  fSingle: single;

  fValue2: double;
  fValue2b: double;
  fValueMax2: double;

begin
  fValue := 7.0207503445953527; 
  fSingle := 7.0207503445953527;
  fValueMax := Max(0, fValue);

  writeln(fValue);       // prints 7.0207503445953527E+000
  writeln(fValueMax);    // prints 7.0207505226135254E+000

  writeln(fSingle);      // prints 7.020750523E+00

  fValue2 := 7.0207503445953527;
  fValue2b := 0.0;
  fValueMax2 := Max(fValue2b, fValue2);

  writeln(fValue2);      // prints 7.0207503445953527E+000
  writeln(fValueMax2);   // prints 7.0207503445953527E+000
  readln;
end.

My first two writeln commands show the same result that you reported seeing. I suspected that perhaps Max was returning a value with less precision that the double you expected to get back, so I created fSingle and assigned it the same literal as you assigned to fValue, and sure enough, its value looks very close to what you're getting back in fValueMax.

So finally, instead of invoking Max with fValue and the literal 0, I called it with two variables of type double, one of which I had set to 0.0. In this case you can see that the input (fValue2) and the output (fValueMax2) have exactly the same value. So while I don't know exactly what Pascal's rules are for determining which overload to call, I wonder if your original call to Max was somehow resolving to the version that takes two single values and returns the same.

While you may be aware of this, I feel compelled to throw in the usual caution about how floating-point types like single and double won't always be able to exactly represent the values you want them to. Here's a good overview.

like image 81
Joe Farrell Avatar answered Feb 26 '26 00:02

Joe Farrell