3

I am learning to program and came across the interesting byproduct of computer number representation shown by $$0.1+0.2= 0.30000000000000004$$

In trying to understand why this occurs, one has to understand how 0.1 is stored on the computer. I worked out that $$0.1_{(10)}=0.00011001100...\,_{(2)}$$ and subsequently read that the number floating-point numbers closest to $0.1$ are $$0.09999999999999999167332731531132594682276248931884765625$$ $$0.1000000000000000055511151231257827021181583404541015625$$ (source: https://stackoverflow.com/a/27030789).

Curious as to how to actually determine these number(s), I attempted to write a python script to find them and failed miserably. I then turned to google and found this answer to a similar question: https://math.stackexchange.com/a/2119191/22276. I was able to follow the solution completely in my case until the portion computing the numbers 14411518807585587 and 14411518807585588. How do I use these numbers to get the two surrounding numbers.

For reference, my two integers would be determined by:

$$2^{-4}=.0625 \leq 0.1 < .125 = 2^{-3}$$ causing $e=-4$. I then compute the integer part of

$$0.1\cdot 2^{53-(-4)}$$ which is $$144 115 188 075 855 872$$

This is where I am stuck.

floater
  • 33

2 Answers2

2

Let $x=0.1, y=0.2, z=0.3$. Let $x', y',z'$ the corresponding values rounded to double precision numbers. You have

    x' = 0.0001100110011001100110011001100110011001100110011001101  (bin)
    x' = 0.1000000000000000055511151231257827021181583404541015625  (dec)
    y' = 0.0011001100110011001100110011001100110011001100110011010  (bin)
    y' = 0.2000000000000000111022302462515654042363166809082031250  (dec)
    z' = 0.0100110011001100110011001100110011001100110011001100110  (bin)
    z' = 0.2999999999999999888977697537484345957636833190917968750  (dec)

Now add $x' + y'$ and get as raw sums

  x'+y' = 0.0100110011001100110011001100110011001100110011001100111 (bin)
  x'+y' = 0.3000000000000000166533453693773481063544750213623046875 (dec)

which would be rounded to

(x'+y')'= 0.010011001100110011001100110011001100110011001100110100 (bin)
(x'+y')'= 0.3000000000000000444089209850062616169452667236328125 (dec)

Not that $x'-x>0$ and $y'-y>0,$ i.e. $x,y$ are rounded-up, while $z'-z <0,$ i.e. $z$ is rounded-down and $x'+ y'$ is rounded-up.

gammatester
  • 18,827
  • This is fantastic. Thank you very much for your write-up. I am thinking that in my post the value below $0.1$ (namely 0.09999999999999999167332731531132594682276248931884765625) is incorrect. Your value of the rounding of x to x' coincides with my calculation whereas my lower value of x comes out as $$0.09999999999999997779553950749686919152736663818359375$$. The latter came from the binary $$0.0001100110011001100110011001100110011001100110011001100$$ – floater Sep 16 '17 at 18:45
  • I just found one aspect that is not clear. When adding the rounded binary forms of 0.1 and 0.2 followed by the raw sum for 0.3 and the rounded form of the raw sum: $$0.0001100110011001100110011001100110011001100110011001101$$ $$0.0011001100110011001100110011001100110011001100110011010$$ $$0.0100110011001100110011001100110011001100110011001100111$$ $$0.0100110011001100110011001100110011001100110011001101$$. It is clear how 0.3 rounds up to this last binary, but it is not clear to me why we lose 3 binary places in the rounding rather than just leave the last three 1s? – floater Sep 16 '17 at 19:05
  • That is, why would the computer choose the rounded sum [i.e., (x'+y')' (bin)] over x'+y' (bin)? – floater Sep 16 '17 at 19:08
  • Nevermind, I figured it out. It is due to the rounding convention of IEEE 754 and gets back to the exponent prefixing the mantissa. – floater Sep 16 '17 at 19:16
  • I was a bit lazy and omitted trailing 0 bits. The mantissa for double precision has 53 bit (where the leading 1 bit is implied). I edited the answer to include the zero bits. (x'+y')' is used because the compiler adds the x' and y' and rounds the result giving ('x+y')'. Note that the raw sum given has more than 53 significant bits, which are round to the 53 bits of (x'+y')'. – gammatester Sep 16 '17 at 19:36
0

I attempted to write a python script to find them and failed miserably.

It's actually quite trivial to display a floating point number exactly in python (I tested with 3.5). Converting a floating point number to a string directly results in a "shortest fit" answer but converting it via a "Decimal" gives the exact answer.

from decimal import Decimal, getcontext
print(Decimal(0.1)) # 0.1000000000000000055511151231257827021181583404541015625 
print(Decimal(0.2)) # 0.200000000000000011102230246251565404236316680908203125

Now lets try adding them together, both exactly and using floating point arithmetic

getcontext().prec = 55 # needed to avoid rounding when we add two Decimal's together.
print(Decimal(0.1)+Decimal(0.2)) # 0.3000000000000000166533453693773481063544750213623046875
print(Decimal(0.1+0.2)) # 0.3000000000000000444089209850062616169452667236328125

We see the floating point arithmetic has resulted in some rounding.

Finally lets check what value we get for the constant 0.3

 print(Decimal(0.3)) # 0.299999999999999988897769753748434595763683319091796875
Peter Green
  • 1,256
  • Since some numbers in base 2 can have infinite trailing numbers in base 10 I think this answer is somewhat flawed – KH Kim Oct 02 '21 at 08:12