Lazarus

Free Pascal => General => Topic started by: littlepaul476 on November 21, 2018, 10:22:43 am

Title: extended type equality
Post by: littlepaul476 on November 21, 2018, 10:22:43 am
Can someone explain to me, why this ended with <NOT OK>? Double or Real alternatives are <OK>.

Code: Pascal  [Select][+][-]
  1. var i,j: extended;
  2. begin
  3.   i:=23500.0*0.032;
  4.   j:=752.0;
  5.   if i=j then
  6.     <OK>
  7.   else
  8.     <NOT OK>;
  9. end;

Lazarus 1.8.4. FPC 3.0.4, Win32
Title: Re: extended type equality
Post by: marcov on November 21, 2018, 10:28:35 am
Floating point math is not exact. 

Extended on 32-bit x86 has more precision, so the deviation from the exact value suddenly fits extended. If you print i you get

7.51999999999999999944E+0002

There is a lot of information about comparing floating point values on the internet, I suggest you read it for a background.

https://floating-point-gui.de/errors/comparison/
https://bitbashing.io/comparing-floats.html

The common trick is to compare with a small deviation (if abs(x-y)<eps then instead of x=y),   free Pascal has a helper routine for that called samevalue (https://www.freepascal.org/docs-html/rtl/math/samevalue.html)
Title: Re: extended type equality
Post by: littlepaul476 on November 21, 2018, 11:28:36 am
Thanks for explanation. I checked values under Watch List and both i and j showed 752. SameValue did the trick, even with default epsilon = 0  :)
Title: Re: extended type equality
Post by: wp on November 21, 2018, 11:35:56 am
SameValue did the trick, even with default epsilon = 0  :)
The default value here is misleading. The value 0 signals to use a standard epsilon depending on the floatingpoint data type. Copied from math.pp:
Code: Pascal  [Select][+][-]
  1. Const
  2.   EZeroResolution = 1E-16;
  3.   DZeroResolution = 1E-12;
  4.   SZeroResolution = 1E-4;
  5.  
  6. function SameValue(const A, B: Extended; Epsilon: Extended): Boolean;
  7. begin
  8.   if (Epsilon=0) then
  9.     Epsilon:=Max(Min(Abs(A),Abs(B))*EZeroResolution,EZeroResolution);
  10.   if (A>B) then
  11.     Result:=((A-B)<=Epsilon)
  12.   else
  13.     Result:=((B-A)<=Epsilon);
  14. end;
Title: Re: extended type equality
Post by: srvaldez on November 21, 2018, 01:38:34 pm
I played with this for a while
changing the expression i:=23500.0*0.032; to i:=23500.0*32/1000; made it work
I thought that casting the literal constant to extended would work, but it made no difference.

Title: Re: extended type equality
Post by: PascalDragon on November 21, 2018, 02:40:59 pm
Simply don't assume that two floating point values are equal (except when checking for special values like 0, +/- Infinity and NaN). Everything else will only lead to problems sooner or later.
Title: Re: extended type equality
Post by: Gammatester on November 21, 2018, 03:35:31 pm
Floating point arithmetic works by rounding the true result to the next representable floating point number (using the selected precision and rounding mode).

With double precision you have
Code: [Select]
0.032 -> 0.0320000000000000006661338147750939242541790008544921875
0.032*23500 -> 752.00000000000001565414464721470721997320652008056640625
The last number is rounded to 752 and with FPC304/Win7 you really get OK!

OTH, for extended precision you get
Code: [Select]
0.032 -> 0.03199999999999999999867185233870525706834087031893432140350341796875
0.032*23500 -> 751.999999999999999968788529959573541106010452494956552982330322265625
The last number is rounded to 751.999999999999999944488848768742172978818416595458984375, and therefore you get NOT OK.

Your expression 23500.0*32/1000 works, because all numbers are (representable as) integers and so the result must be an integer.
TinyPortal © 2005-2018