Recent

Author Topic: min() function behavior inconsistent  (Read 2006 times)

han

  • Jr. Member
  • **
  • Posts: 96
min() function behavior inconsistent
« on: May 29, 2023, 10:09:42 pm »
I have problem with the math library min() function. Noticed the following:

Code: Pascal  [Select][+][-]
  1. var
  2.   a,b,c: double;
  3.  
  4. begin
  5.    a:=1;
  6.    b:=0.99999999;
  7.    c:=min(a,b);  //results in 0.99999999;
  8.    c:=min(1.0,b);//results in 0.99999999;
  9.    c:=min(1,b);//results in 1  Why is this not working?
  10.    c:=min(b,1);//results in 1  Why is this not working?
  11.  
  12.    b:=0.9999999;
  13.    c:=min(1,b);//results in c = 0.99999988079071
  14. end.  

The solution is to write 1.0, but b is a double. So why is it not using this function????:

Code: Pascal  [Select][+][-]
  1. function Min(a, b: Double): Double;inline;
  2. begin
  3.   if a < b then
  4.     Result := a
  5.   else
  6.     Result := b;
  7. end;
 

Han



marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11353
  • FPC developer.
Re: min() function behavior inconsistent
« Reply #1 on: May 29, 2023, 10:23:15 pm »
Probably if the first argument fits in single, single precision is chosen

han

  • Jr. Member
  • **
  • Posts: 96
Re: min() function behavior inconsistent
« Reply #2 on: May 30, 2023, 10:17:37 am »
Yes I had the same impression. But is that the correct behavior if the second variable is a double? Secondly why is for the 1.0 not a single selected?

jamie

  • Hero Member
  • *****
  • Posts: 6077
Re: min() function behavior inconsistent
« Reply #3 on: May 30, 2023, 12:29:40 pm »
Try.

min(1.0,B); etc.

The only true wisdom is knowing you know nothing

wp

  • Hero Member
  • *****
  • Posts: 11833
Re: min() function behavior inconsistent
« Reply #4 on: May 30, 2023, 12:35:39 pm »
My impression is that Pascal no longer is a "type-safe" programming language due to these implicit type conversions. I am afraid there are tons of bugs in user (and official) code based on this. I wish there were a compiler switch enforcing real type-safe operation, i.e. Min(1, b) should cause a compilation error because it mixes integer and double arguments.

440bx

  • Hero Member
  • *****
  • Posts: 3921
Re: min() function behavior inconsistent
« Reply #5 on: May 30, 2023, 01:10:00 pm »
My impression is that Pascal no longer is a "type-safe" programming language due to these implicit type conversions.
Particularly when the conversions are either from integer to real or vice versa (for fairly obvious reasons.)

That said, since the parameter of the "min" function is a double, it is reasonable to expect the compiler to promote the integer to double but, apparently that's not what happened (otherwise 1 and 1.0 would yield the same result.)

I'd say there is at least an inconsistency there.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

jamie

  • Hero Member
  • *****
  • Posts: 6077
Re: min() function behavior inconsistent
« Reply #6 on: May 30, 2023, 01:51:29 pm »
Delphi seems to work better in that regard.

 Its all about what happens inside of the closer of the function/procedure. Things do not behave the same as they do if you are explicitly assigning to a double type.

 Constants should be fluid to what they are being used for. This would solve the other issues of compiler magically converting non integer math results to integers and picking the wrong overloads.

 I can go, but I won't.
« Last Edit: May 30, 2023, 01:53:24 pm by jamie »
The only true wisdom is knowing you know nothing

Kays

  • Hero Member
  • *****
  • Posts: 569
  • Whasup!?
    • KaiBurghardt.de
Re: min() function behavior inconsistent
« Reply #7 on: May 30, 2023, 05:37:17 pm »
I have problem with the math library min() function. Noticed the following: […]
Good question.
  • On x86‑64 the SSE2 instructions are preferred over the “legacy” x87 FPU instructions. The actual comparison is performed by the comisd instruction (compare scalar ordered double-precision floating-point values and set EFLAGS).
  • The FPC prefers storing constants in the least amount of Bytes necessary. Thus the integer value 1 to your call of min is converted to a real value at compile-time, but since it fits into single without any loss in precision it is stored as single.
  • Now we have a single value and a double value. There is no instruction comparing FP-values of differing precision. You would expect the common denominator is double, but for some inexplicably ill-conceived reason commiss is used (compare two single values) so the value of b gets temporarily demoted to a single (cvtsd2ss). This leads to rounding errors; you end up comparing 1.0 with 1.0 hence the result of 1.0.
I claim this is a bug. “Covert” data type demotion only makes sense if it is not at a loss of information.

My impression is that Pascal no longer is a "type-safe" programming language due to these implicit type conversions. […]
The promotion of numbers – ℤ → ℝ → ℂ – has always been there. Any demotion must be explicit as evidenced by the existence of trunc, round, re, im, arg and abs. Implicit demotion is indeed very un‑Pascal‑ish.
« Last Edit: May 31, 2023, 11:19:16 am by Kays »
Yours Sincerely
Kai Burghardt

Blaazen

  • Hero Member
  • *****
  • Posts: 3237
  • POKE 54296,15
    • Eye-Candy Controls
Re: min() function behavior inconsistent
« Reply #8 on: May 30, 2023, 07:05:06 pm »
This compares pears and apples:
Code: Pascal  [Select][+][-]
  1.   c:=min(1,b);
  2.   c:=min(b,1);
Should be 1.0 or double(1). If FPC would be strictly type safe, the code above would not compile at all. Other option is to define more overloaded functions, min(Integer, Double); etc.
Lazarus 2.3.0 (rev main-2_3-2863...) FPC 3.3.1 x86_64-linux-qt Chakra, Qt 4.8.7/5.13.2, Plasma 5.17.3
Lazarus 1.8.2 r57369 FPC 3.0.4 i386-win32-win32/win64 Wine 3.21

Try Eye-Candy Controls: https://sourceforge.net/projects/eccontrols/files/

tetrastes

  • Sr. Member
  • ****
  • Posts: 469
Re: min() function behavior inconsistent
« Reply #9 on: May 30, 2023, 09:29:05 pm »
  • On x86‑64 the SSE2 instructions are preferred over the “legacy” x87 FPU instructions. The actual comparison is performed by the comisd instruction (compare scalar ordered double-precision floating-point values and set EFLAGS).
i386 binary with x87 instructions gives the same results. The problem is that compiler makes the wrong choose of min().

  • The FPC prefers storing constants in the least amount of Bytes necessary. Thus the integer value 1 to your call of min is converted to a real value at compile-time, but since it fits into single without any loss in precision it is stored as single.
But this is also true for constant 1.0, it is stored as single. So in min(1.0, b) we have a single value and a double value also, but compiler generates comparison for doubles.

I claim this is a bug. “Covert” data type demotion only makes sense if it is not at a loss of information.
Fully agree.

tetrastes

  • Sr. Member
  • ****
  • Posts: 469
Re: min() function behavior inconsistent
« Reply #10 on: May 30, 2023, 09:44:09 pm »
This compares pears and apples:
Code: Pascal  [Select][+][-]
  1.   c:=min(1,b);
  2.   c:=min(b,1);
Should be 1.0 or double(1).
Or single(1)  %)

EDIT: double(1) and single(1) work only in trunk, in fpc 3.2.2 these give something different from what one may expect  :D (IIRC it was discussed somewhere in this forum).
« Last Edit: May 30, 2023, 10:41:22 pm by tetrastes »

Zoran

  • Hero Member
  • *****
  • Posts: 1829
    • http://wiki.lazarus.freepascal.org/User:Zoran
Re: min() function behavior inconsistent
« Reply #11 on: May 30, 2023, 10:07:32 pm »

See this test programme:

Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. procedure Test(A: Single; B: Single);
  6. begin
  7.   WriteLn(': Single, Single called');
  8. end;
  9.  
  10. procedure Test(A: Double; B: Double);
  11. begin
  12.   WriteLn(': Double, Double called');
  13. end;
  14.  
  15. var
  16.   S: Single;
  17.   D: Double;
  18.   I64: Int64;
  19. begin
  20.   S := 1.0;
  21.   D := 1.0;
  22.   I64 := 1;
  23.  
  24.   Write('I64, S'); // when we pass Int64 and Single arguments
  25.   Test(I64, S); // Single, Single called
  26.  
  27.   Write('S, D'); // with single and double, single gets prompoted
  28.   Test(S, D); // Double, Double called
  29.  
  30.   Write('I64, D'); // but not with Int64, we get:
  31.   Test(I64, D); // Single, Single called!!!?????!!!!!
  32.  
  33.   Write('D, I64'); // Even with double parameter first, we get
  34.   Test(D, I64); // Single, Single called!!!?????!!!!!
  35.  
  36.   ReadLn;
  37. end.
  38.  

The output:
Quote
I64, S: Single, Single called
S, D: Double, Double called
I64, D: Single, Single called
D, I64: Single, Single called

We can see that, when we pass Single and Double parameters, Double overload is chosen (Single gets promoted).
Therefore, even if Integer is promoted to Single, when passed with double, I would expect it to behave same as when Single and Double are passed together. But it does not. So, I agree that this has to be regarded as a bug.


han

  • Jr. Member
  • **
  • Posts: 96
Re: min() function behavior inconsistent
« Reply #12 on: May 30, 2023, 10:20:23 pm »
Thanks Zoran,

Yes looks like the 1 is processed as a single and the 1.0 as a double.

I have created an issue and added your post and test program. Thanks.

https://gitlab.com/freepascal.org/fpc/source/-/issues/40302
« Last Edit: May 30, 2023, 10:42:08 pm by han »

tetrastes

  • Sr. Member
  • ****
  • Posts: 469
Re: min() function behavior inconsistent
« Reply #13 on: May 31, 2023, 12:12:14 am »
About type-safety and implicit type conversion:
Code: Pascal  [Select][+][-]
  1. var
  2.     b: byte;
  3.     c: char;
  4.     d: double;
  5.     s: single;
  6. . . .
  7.  
  8.     b := c;  // is not compiled
  9.     b := byte(c);  // is compiled
  10.     c := b;   // is not compiled
  11.     c := char(b);  // is compiled
  12.     d := s;  // is compiled
  13.     d := double(s);  // is not compiled
  14.     s := d;  // is compiled
  15.     s := single(d);  // is not compiled

Isn't this a mess?  :D

440bx

  • Hero Member
  • *****
  • Posts: 3921
Re: min() function behavior inconsistent
« Reply #14 on: May 31, 2023, 12:15:32 am »
Isn't this a mess?  :D
Have you or anyone else tested what a recent/current version of Delphi does with that test case ? 

It would be interesting to see how Delphi handles it.

(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

 

TinyPortal © 2005-2018