7

So I think I basically understand how floating-point works and why we can't have "precise" results for some operations.

I got confused by this SO-question, where @MikeMüller suggests rounding.


My understanding is the following. If we write decimal places it would look like this:
1000 100 10 1 . 1/10 1/100 1/1000

It would look like this in binary:
8 4 2 1 . 1/2 1/4 1/8

So we store 0.5 or 0.25 or 0.125 precisely in memory but not e.g. 0.3

So why does python output the following:

print(0.1)
print(0.2)
print(0.3)
print(0.1 + 0.2)

>>>0.1
>>>0.2
>>>0.3
>>>0.30000000000000004

I think it should output

>>>0.1
>>>0.2
>>>0.30000000000000004
>>>0.30000000000000004

Where am I wrong?


My Question is NOT a duplicate of Is floating point math broken? because OP does not understand why 0.1+0.2 != 0.3. This is not topic of my question!

Community
  • 1
  • 1
JDurstberger
  • 4,127
  • 8
  • 31
  • 68
  • 4
    Possible duplicate of [Is floating point math broken?](http://stackoverflow.com/questions/588004/is-floating-point-math-broken) – khelwood Feb 04 '16 at 11:09
  • Why is that? 1/10 and 2/10 are not exactly representable as a binary fraction. Almost all machines today (July 2010) use IEEE-754 floating point arithmetic, and almost all platforms map Python floats to IEEE-754 “double precision”. 754 doubles contain 53 bits of precision, so on input the computer strives to convert 0.1 to the closest fraction it can of the form J/2**N where J is an integer containing exactly 53 bits. Rewriting https://docs.python.org/2/tutorial/floatingpoint.html#representation-error – Laser Feb 04 '16 at 11:15
  • 3
    They are NOT duplicates, closing this is a MISTAKE! – peterh Feb 04 '16 at 11:25
  • @peterh Thank you, I think the same... – JDurstberger Feb 04 '16 at 11:30

3 Answers3

12

Because they're not the same, as 0.1 and 0.2 isn't correctly represented already. So:

>>>print("%.20f" % (0.1+0.2))
0.30000000000000004441

>>>print("%.20f" % 0.3)
0.29999999999999998890

>>>print(0.29999999999999998890)
0.3

So it's all up to the Python rules for printing stuff, especially considering that pure 0.3 representation is much closer to actual 0.3 than 0.1 + 0.2.

Here's the related excerpt from Python docs:

Interestingly, there are many different decimal numbers that share the same nearest approximate binary fraction. For example, the numbers 0.1 and 0.10000000000000001 and 0.1000000000000000055511151231257827021181583404541015625 are all approximated by 3602879701896397 / 2 ** 55. Since all of these decimal values share the same approximation, any one of them could be displayed while still preserving the invariant eval(repr(x)) == x.

Historically, the Python prompt and built-in repr() function would choose the one with 17 significant digits, 0.10000000000000001. Starting with Python 3.1, Python (on most systems) is now able to choose the shortest of these and simply display 0.1.

TNW
  • 716
  • 6
  • 15
1

From the docs on floating point in Python 3,

Interestingly, there are many different decimal numbers that share the same nearest approximate binary fraction. For example, the numbers 0.1 and 0.10000000000000001 and 0.1000000000000000055511151231257827021181583404541015625 are all approximated by 3602879701896397 / 2 ** 55. Since all of these decimal values share the same approximation, any one of them could be displayed while still preserving the invariant eval(repr(x)) == x.

Historically, the Python prompt and built-in repr() function would choose the one with 17 significant digits, 0.10000000000000001. Starting with Python 3.1, Python (on most systems) is now able to choose the shortest of these and simply display 0.1.

So that is why it shows 0.3 when it can -- because that is the shortest string that is stored as that binary representation. The slightly higher result of 0.1 + 0.2 cannot be shown as a shorter string than 0.30000000000000004.

Community
  • 1
  • 1
RemcoGerlich
  • 30,470
  • 6
  • 61
  • 79
-1

To make the rounding problems no so visible, normally floating point numbers are printed without their last digit, which is rounded. This is exactly to hide the problems you wish to see.

So, 0.30000000000000004 will be rounded to 0.3.

But you can easily reproduce the problem if you make intentionally such a calculation which avoids this rounding. For example, multiple the result with 1e+6. And you will see, what you see.

peterh
  • 11,875
  • 18
  • 85
  • 108