Recent

Author Topic: extended type equality  (Read 1785 times)

littlepaul476

  • New member
  • *
  • Posts: 9
extended type equality
« 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
« Last Edit: November 21, 2018, 10:24:14 am by littlepaul476 »

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 7507
Re: extended type equality
« Reply #1 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

littlepaul476

  • New member
  • *
  • Posts: 9
Re: extended type equality
« Reply #2 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  :)

wp

  • Hero Member
  • *****
  • Posts: 6351
Re: extended type equality
« Reply #3 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;
Lazarus trunk / fpc 3.0.4 / all 32-bit on Win-10

srvaldez

  • New member
  • *
  • Posts: 5
Re: extended type equality
« Reply #4 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.


PascalDragon

  • Hero Member
  • *****
  • Posts: 674
  • Compiler Developer
Re: extended type equality
« Reply #5 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.

Gammatester

  • Jr. Member
  • **
  • Posts: 69
Re: extended type equality
« Reply #6 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.
« Last Edit: November 21, 2018, 03:52:59 pm by Gammatester »