2

Possible Duplicate:
Floating Point Limitations

Using Python 2.7 here.

Can someone explain why this happens in the shell?

>>> 5.2-5.0
0.20000000000000018

Searching yielded things about different scales of numbers not producing the right results (a very small number and a very large number), but that seemed pretty general, and considering the numbers I'm using are of the same scale, I don't think that's why this happens.

EDIT: I suppose I didn't define that the "this thing happening" I meant was that it returns 0.2 ... 018 instead of simply resulting in 0.2. I get that print rounds, and removed the print part in the code snippet, as that was misleading.

Community
  • 1
  • 1
adamjseitz
  • 125
  • 1
  • 1
  • 7
  • There are really three parts to this question: "Why is `5.2 - 5.0 != 0.2`", "Why does evaluating the expression not do the same as printing it", and "Why/how are the repr and str different"? My answer focuses on part 1, Ashwini Chaudhary's is a perfect answer to part 2, and Martijn Pieters's nicely handles part 3. – abarnert Sep 25 '12 at 22:09
  • See http://docs.python.org/tutorial/floatingpoint.html . It's a much gentler introduction to the issues than the Goldberg paper. – Mark Dickinson Sep 26 '12 at 05:49

4 Answers4

5

You need to understand that 5.2-5.0 really is 0.20000000000000018, not 0.2. The standard explanation for this is found in What Every Computer Scientist Should Know About Floating-Point Arithmetic.

If you don't want to read all of that, just accept that 5.2, 5.0, and 0.20000000000000018 are all just approximations, as close as the computer can get to the numbers you really way.

Python has some tricks to allow you to not know what every computer scientist should know and still get away with it. The main trick is that str(f)—that is, the human-readable rendition of a floating-point number—is truncated to 12 significant digits, so str(5.2-5.0) is "0.2", not "0.20000000000000018". But sometimes you need all the precision you can get, so repr(f)—that is, the machine-readable rendition—is not truncated, so repr(5.2-5.0) is "0.20000000000000018".

Now the only thing left to understand is what the interpreter shell does. As Ashwini Chaudhary explains, just evaluating something in the shell prints out its repr, while the print statement prints out its str.

abarnert
  • 354,177
  • 51
  • 601
  • 671
2

shell uses repr():

In [1]: print repr(5.2-5.0)
0.20000000000000018

In [2]: print str(5.2-5.0)
0.2

In [3]: print 5.2-5.0
0.2
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
  • I apologize, I didn't make my question very clear. I want to know why 5.2-5.0 doesn't simply result in 0.2? – adamjseitz Sep 25 '12 at 22:03
1

The default implementation of float.__str__ limits the output to 12 digits only.

Thus, the least significant digits are dropped and what is left is the value 0.2.

To print more digits (if available), use string formatting:

print '%f' % result  # prints 0.200000

That defaults to 6 digits, but you can specify more precision:

print '%.16f' % result  # prints 0.2000000000000002

Alternatively, python offers a newer string formatting method too:

print '{0:.16f}'.format(result)  # prints 0.2000000000000002

Why python produces the 'imprecise' result in the first place has everything to do with the imprecise nature of floating point arithmetic. Use the decimal module instead if you need more predictable precision:

>>> from decimal import *
>>> getcontext().prec = 1
>>> Decimal(5.2) - Decimal(5.0)
Decimal('0.2')
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
0

Python has two different ways of converting an object to a string, the __str__ and __repr__ methods. __str__ is meant to be a normal string output and is used by print; __repr__ is meant to be a more exact representation and is what is displayed when you don't use print, or when you print the contents of a list or dictionary. __str__ rounds floating-point values.

As for why the actual result of the subtraction is 0.20000000000000018 rather than 0.2 exactly, it has to do with the internal representation of floating point. It's impossible to represent 5.2 exactly because it's an infinitely repeating binary number. The closest that you can come is approximately 5.20000000000000018.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622