Why does 0.1 + 0.1 + 0.1 - 0.3 evaluate to
5.5511151231257827e-17 in Python?
-
Agreed Precision wil vary... but here 5.5511151231257827e-17 is incorrect!!Nitish Upreti– Nitish Upreti2009-12-12 11:27:21 +00:00Commented Dec 12, 2009 at 11:27
-
3While not wanting to take anything away from the answers below, 5.55e-17 is really a small quantity and would be regarded as zero in most practical situations.pavium– pavium2009-12-12 11:27:48 +00:00Commented Dec 12, 2009 at 11:27
-
2In case you don't understand the notation, the number you see means 0.000000000000000055511151231257827. Very small.Artelius– Artelius2009-12-12 11:29:51 +00:00Commented Dec 12, 2009 at 11:29
-
60.1 is not representable exactly in any precision of a IEEE-754 floating-point format. You could use 128-bit extended doubles and still have the same problem, only the exponent would be even smaller.Pascal Cuoq– Pascal Cuoq2009-12-12 11:30:00 +00:00Commented Dec 12, 2009 at 11:30
-
1just for fun I tried it in Python, Lua, Perl and Ruby. they all show the same result: 5.55111512312578e-17Javier– Javier2009-12-12 11:50:25 +00:00Commented Dec 12, 2009 at 11:50
6 Answers
Because that's how floating point numbers work. If you want precise numbers, use the decimal module. If you want to use floating point numbers, you have to remember to round them to a specific precision when you are displaying them.
>>> print '%.2f' % (0.1+0.1+0.1-0.3,)
0.00
3 Comments
float type in Python.This is a problem with floating point numbers in general. See this section on Wikipedia for a description. Roughly speaking - there are rounding errors. Notice that the number you gave us was very small - about 0.00000000000000005551115123 . Here is a more technical paper about the subject.
Comments
The answer is here: What Every Computer Scientist Should Know About Floating-Point Arithmetic
Comments
You might be interested in knowing that Python 3 has improved the situation by changing how repr works. It will now give you the shortest string representation that will be converted back to the original float:
Python 3.1.1+ (r311:74480, Oct 11 2009, 20:19:13) [GCC 4.3.4] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> 0.1 '0.1'
Older versions behave like this:
Python 2.6.4 (r264:75706, Oct 28 2009, 22:19:17) [GCC 4.3.4] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> 0.1 '0.10000000000000001'
It is only the output of repr (called implicitly when you enter a value in the interactive interpreter) that has changed. The underlying values are still IEEE-754 floating-point numbers, and they still have the usual limitations:
Python 3.1.1+ (r311:74480, Oct 11 2009, 20:19:13) [GCC 4.3.4] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> 0.1 0.1 >>> 0.2 0.2 >>> 0.3 0.3 >>> 0.1 + 0.2 0.30000000000000004 >>> 0.1 + 0.2 - 0.3 5.551115123125783e-17
Comments
Because of the way floating points numbers are represented in a computer. It's not just a Python thing.
2 Comments
System.out.println rounds the number, which is exactly what the Python code in my answer does.As an example, consider representing 1/3 as a scientific number in base 10. With only a finite number of digits (say, 10), you'll wind up with a rounding error. Say 1/3 ≈ 0.3333333333e0. Then 1/3+1/3+1/3 (after first converting to decimal expansions) is represented as 0.9999999999e0, but 1 is 1.0e0. Similarly, 1/7 ≈ 0.1428571429e0, and 1/7+1/7 would be 0.2857142858e0, but the representation for 2/7 would be 0.2857142857e0. In both cases, the sum is off by 1e-10.