Recent

Author Topic: double type significant digits  (Read 3500 times)

apeoperaio

  • Sr. Member
  • ****
  • Posts: 272
double type significant digits
« on: September 17, 2018, 11:44:02 am »
Dear all,

I have an issue using Double type that I cannot understand.
I have an application running on linux and windows. I get different results on the two OS.
It seems something related to error propagation and an unexpected use of significant digits.

I tested the code below on windows and since Double has a maximum of 16 significant digits I cannot understand why the two results are different.

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   a, b, c, d: double;
  4. begin
  5.   // doiuble has 16 significant digits?
  6.   a:= 25.144927032417762; // --> shouldn't be stored as  25.14492703241776 ?
  7.   b:= 10.99988788760643;  // --> shouldn't be stored as  10.99988788760643 ?
  8.   c:= 25.144927032417762; // --> shouldn't be stored as  25.14492703241776 ?
  9.   d:= a+b+c;
  10.   Label1.Caption:= FloatToStr(d);  // --> 61.289741952442 (shouldn't be correct only this?)
  11.   a:= 25.144927032417758; // --> shouldn't be stored as  25.14492703241776 ?
  12.   b:= 10.99988788760643;  // --> shouldn't be stored as  10.99988788760643 ?
  13.   c:= 25.144927032417758; // --> shouldn't be stored as  25.14492703241776 ?
  14.   d:= a+b+c;
  15.   Label2.Caption:= FloatToStr(d); // -->  61.2897419524419 (wrong?)
  16. end;  
  17.  

Am I missing something?

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: double type significant digits
« Reply #1 on: September 17, 2018, 03:06:19 pm »

The first number is stored as:

Code: Pascal  [Select][+][-]
  1. # value: 0d+2.5144927032417762E+001
  2.         .byte   102,138,32,240,25,37,57,64
  3.  

the other as
Code: Pascal  [Select][+][-]
  1. # value: 0d+2.5144927032417758E+001
  2.         .byte   101,138,32,240,25,37,57,64
  3.  

iow, rounded down.

apeoperaio

  • Sr. Member
  • ****
  • Posts: 272
Re: double type significant digits
« Reply #2 on: September 17, 2018, 03:17:58 pm »
How can you get those values?
Do you mean than 25.144927032417758 is stored as 25.14492703241775?
Why?

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: double type significant digits
« Reply #3 on: September 17, 2018, 03:36:44 pm »
How can you get those values?

Compile with -al, check generated assembler source.

Quote
Do you mean than 25.144927032417758 is stored as 25.14492703241775?
Why?

Floating point is binary, not decimal. Rounded down to the floating point value that has the lowest bit one lower.

This can be seen in the change from 102 to 101 in the code that I quoted. The first byte is probably the least significant of the mantissa, and that went from binary  "10" at the end to "01".   

apeoperaio

  • Sr. Member
  • ****
  • Posts: 272
Re: double type significant digits
« Reply #4 on: September 17, 2018, 04:00:57 pm »
Why is it rounded to  the lo lowest  and not to the nearest?

ccrause

  • Hero Member
  • *****
  • Posts: 845
Re: double type significant digits
« Reply #5 on: September 17, 2018, 04:50:28 pm »
Why is it rounded to  the lo lowest  and not to the nearest?
Several rounding methods are defined by IEEE 754 (see wikipedia).  The FPU rounding mode can be set using the FPU control word - it is therefore conceivable that different programs (or operating systems) could initialize to different rounding rules, resulting in small discrepancies between results.

I assume marcov was alluding to this effect when mentioning:
iow, rounded down.

Gammatester

  • Jr. Member
  • **
  • Posts: 69
Re: double type significant digits
« Reply #6 on: September 17, 2018, 05:26:25 pm »
How can you get those values?
Do you mean than 25.144927032417758 is stored as 25.14492703241775?
Why?
Both values are not exactly representable as double. The nearest (stored) double values are
Code: [Select]
25.144927032417758  =>  25.144927032417758283600051072426140308380126953125
25.144927032417762  =>  25.14492703241776183631372987292706966400146484375
and the corresponding sums are
Code: [Select]
61.289741952441953998231838340871036052703857421875
61.289741952441946892804480739869177341461181640625
« Last Edit: September 17, 2018, 05:33:47 pm by Gammatester »

apeoperaio

  • Sr. Member
  • ****
  • Posts: 272
Re: double type significant digits
« Reply #7 on: September 19, 2018, 08:51:25 am »
Thanks for the explanation. I got it.
I will try to replicate my issue, since I get different values on Linux and Windows as result of the same expression.

apeoperaio

  • Sr. Member
  • ****
  • Posts: 272
Re: double type significant digits
« Reply #8 on: September 19, 2018, 09:26:06 am »
Both values are not exactly representable as double. The nearest (stored) double values are
Code: [Select]
25.144927032417758  =>  25.144927032417758283600051072426140308380126953125
25.144927032417762  =>  25.14492703241776183631372987292706966400146484375
and the corresponding sums are
Code: [Select]
61.289741952441953998231838340871036052703857421875
61.289741952441946892804480739869177341461181640625

How can I get those values using the debugger?

Gammatester

  • Jr. Member
  • **
  • Posts: 69
Re: double type significant digits
« Reply #9 on: September 19, 2018, 10:35:19 am »
How can I get those values using the debugger?
I guess it is difficult to get the numbers in the debugger (may be one can write some extensions, I do not know).

You can reproduce the numbers with a multiprecision calculator, that is able to represent IEEE floating point numbers. I use my open source MPArith (http://www.wolfgang-ehrhardt.de/misc_en.html#mparith) calculator t_rcalc (http://www.wolfgang-ehrhardt.de/mp_intro.html#t_rcalc)

Here the mapping double -> mp_float is done with the asd function, which computes the nearest double to the argument.

This is the logging of the calculation for your numbers
Code: [Select]
D:\Math\xx>t_rcalc.exe
Test of MPArith V1.38.10 (31/32 bit) [mp_rcalc]   (c) W.Ehrhardt 2008-2018
Karatsuba  cutoffs: mul/sqr = 16/32
Toom-3, BZ cutoffs: mul/sqr = 32/64,  div = 32
Type "?<enter>" to get some info about commands, "\q" or "quit" to end.
Current bit precision = 240 (max:120000),  decimal precision = 72.2

[D]:=> x = asd(25.144927032417758)
X = 25.144927032417758283600051072426140308380126953125
[D]:=> y = asd(25.144927032417762)
Y = 25.14492703241776183631372987292706966400146484375
[D]:=> z = asd(10.99988788760643)
Z = 10.999887887606430325604378595016896724700927734375
[D]:=> x + z +x
Result = 61.289741952441946892804480739869177341461181640625
[D]:=> y + z +y
Result = 61.289741952441953998231838340871036052703857421875
« Last Edit: September 19, 2018, 10:37:56 am by Gammatester »

apeoperaio

  • Sr. Member
  • ****
  • Posts: 272
Re: double type significant digits
« Reply #10 on: September 19, 2018, 10:40:00 am »
I will have a look, thanks!

 

TinyPortal © 2005-2018