Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does print(0.3) print 0.3 and not 0.30000000000000004

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!

like image 691
JDurstberger Avatar asked Feb 04 '16 11:02

JDurstberger


2 Answers

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.

like image 103
TNW Avatar answered Dec 10 '22 18:12

TNW


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.

like image 42
RemcoGerlich Avatar answered Dec 10 '22 18:12

RemcoGerlich