In Python, these expressions produce surprising results:
print(0.1 + 0.2 == 0.3) # False
print(0.1 + 0.1 == 0.2) # True
print(sum([0.1] * 10000) == 1000) # True in some Python versions
I understand that decimal values such as 0.1 usually cannot be represented exactly in binary IEEE 754 floating-point format. However, I expected repeatedly adding 0.1 to make the error increasingly obvious. Why do some of these comparisons evaluate to True while others evaluate to False? Is the behavior specific to Python, and how should floating-point values be compared safely?
3 Answers
This is not unique to Python. Computers store floating-point numbers with a finite number of binary digits, and fractions such as 1/10 have repeating representations in base 2, just as 1/3 repeats in base 10. Every operation rounds its result to a representable value. Whether the final result matches another separately rounded value depends on the exact intermediate values and rounding steps.
The stored value for 0.1 is actually a nearby binary approximation, roughly 0.10000000000000000555. When two approximations are added, the result is rounded to the nearest representable floating-point value. In this case, 0.1 + 0.1 rounds to exactly the same stored value as 0.2, so the comparison succeeds. The result of 0.1 + 0.2, however, rounds to a value slightly different from the stored value for 0.3, so that comparison fails. Floating-point errors do not simply grow in a predictable linear way; rounding can sometimes make them cancel and sometimes make them more noticeable.
The behavior of sum([0.1] * 10000) depends on the Python version and the algorithm used by sum(). A simple loop such as this will commonly show accumulated error:
total = 0.0
for _ in range(10000):
total += 0.1
print(total == 1000)
Newer Python versions use a more accurate summation strategy for built-in sum() on floating-point values, which can produce 1000 exactly in this example. That does not mean 0.1 is represented exactly; it means the summation algorithm manages rounding error more effectively. For ordinary calculations, compare with a tolerance, for example abs(value - target) <= epsilon, or use math.isclose(). For financial or exact decimal calculations, consider decimal.Decimal instead.

A useful decimal analogy is using only three decimal places: 1/3 becomes 0.333 and 2/3 becomes 0.667. Adding those gives 1.000, but adding 0.333 + 0.333 gives 0.666 instead of the rounded value 0.667. Small approximation errors can cancel in one calculation and reinforce each other in another.