1

When using list comprehension expression:

[x * 0.1 for x in range(0, 5)]

I expect to get a list like this:

[0.0, 0.1, 0.2, 0.3, 0.4]

However I instead I get this:

[0.0, 0.1, 0.2, 0.30000000000000004, 0.4]

What is the reason behind this?

Chris Martin
  • 30,334
  • 10
  • 78
  • 137
Alec Hewitt
  • 805
  • 1
  • 12
  • 21
  • 4
    http://docs.python.org/2/tutorial/floatingpoint.html – Markon May 14 '13 at 19:21
  • @MartijnPieters: It's only a dup if you ignore the fact that the OP mistakenly thought the list comprehension was part of the problem. The question is whether future searchers/readers are likely to have the same mistaken impression. – abarnert May 14 '13 at 19:43
  • Step 1 or 2 of trying to solve this question should be "try it without a list comprehension to see if the results hold", @abarnert, so I believe the duplicate proposal is correct. – jscs May 14 '13 at 19:46
  • 2
    @abarnert: The problem is still the floating point rounding error. Someone else thinking they have the same problem will find this question, then be pointed to the dupe question to see that floating point errors can occur without list comprehensions too. Which is the point. – Martijn Pieters May 14 '13 at 19:50

3 Answers3

4

floats are inherently imprecise in pretty much every language

if you need exact precision use the Decimal class

from decimal import Decimal
print Decimal("0.3")

if you just need them to look pretty just use format strings when displaying eg :

"%0.2f"%2.030000000000034

if you want to compare them use some threshold

if num1 - num2 < 1e-3 : print "Equal Enough For Me!"

**see abarnert's comments on thresholding ... this is a very simplified example for a more indepth explanation of epsilon thresholding one article I found is here http://www.cygnus-software.com/papers/comparingfloats/Comparing%20floating%20point%20numbers.htm

Additional Reading:

http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html (for a detailed explanation)

http://floating-point-gui.de/basic/ (basic tutorial for working with floats in general)

Joran Beasley
  • 110,522
  • 12
  • 160
  • 179
  • 1
    Exactly - this has nothing to do with the list comprehension. (Well, I'm not sure I'd call python floats "accurate" to any specific precision without a clearer definition of "accurate".) You get the same imprecise result if you just directly evaluate 0.1 * 3. – Peter DeGlopper May 14 '13 at 19:23
  • "floats are accurate up to 9 places after the decimal" is wrong. For example, `float(1<<64)+.1 == float(1<<64)` is `True`—it's not even accurate to _1_ place after the decimal. – abarnert May 14 '13 at 19:30
  • Also, similarly, if you don't have some out-of-band way of knowing the scale you care about, you often need something like `num1 - num2 < 1e-3 * max(num1, num2)` (or `gmean` or some other function, depending on the case). And of course this only works for positive numbers, because you forgot the `abs`. I think it would be better to link to some discussion of epsilon thresholding or error analysis than to try to explain it in one line. – abarnert May 14 '13 at 19:33
  • your right ... removed wrong part ... I coulda sworn I read somewhere that python guaranteed floats up to X precision ... but meh – Joran Beasley May 14 '13 at 19:34
  • 1
    @JoranBeasley: Up to X precision means the number of _significant_ digits, not the number of _fractional_ digits. Also, Python's docs speak a bit loosely: if you take subnormals into account, the number of significant digits in an IEEE double can be less than 1. – abarnert May 14 '13 at 19:36
  • @JoranBeasley: Also, you might want to add the tutorial link and Goldberg link to the answer, so this one answer is sufficient without people having to read the later ones as well. – abarnert May 14 '13 at 19:38
  • done :) as always good suggestions :) – Joran Beasley May 14 '13 at 19:42
2

List comprehension does not matter.

>>> 3 * 0.1
0.30000000000000004
>>> 2 * 0.1
0.2
>>> 0.1 + 0.2
0.30000000000000004

More information about Python float and floating point arithmetic - here

Alexey Kachayev
  • 6,106
  • 27
  • 24
1

The list comprehension is irrelevant, this is purely an issue with floating-point numbers. For an extremely detailed answer you should give this article a read: http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

Kevin D
  • 431
  • 4
  • 7