Python Floating Point Math: What 0.1 + 0.2 Really Means
Explains why Python's floating-point math produces results like 0.30000000000000004, covers IEEE 754 representation, practical workarounds using math.isclose and Decimal, and when precision matters most for developers.
The Surprising Truth About Python's Floating Point Math
When a new developer at PythonSkillset first runs 0.1 + 0.2 and gets 0.30000000000000004, they often think their computer is broken. But it's not broken - it's actually working exactly as designed. This isn't a Python quirk either. It's a fundamental property of how computers handle decimal numbers.
Why Computers Can't Count Perfectly
Here's the thing: computers work in binary (base-2), but humans count in decimal (base-10). Most decimal fractions can't be represented exactly in binary, just like how 1/3 can't be written as a clean decimal (it's 0.33333...).
Think about it this way: In decimal, we can write 1/10 as 0.1 - clean and simple. But in binary, 1/10 becomes an infinitely repeating number: 0.0001100110011... The computer has to cut this off somewhere, which introduces tiny errors.
Python's Approach: Float Is Just a Name
In Python, floating-point numbers are implemented using the double-precision IEEE 754 standard. This gives you about 15-17 decimal digits of precision. The keyword float in Python maps directly to the C double type - it's not really a "float" at all by traditional C definitions.
Here's a practical example from PythonSkillset's teaching code:
# You might expect this to be True
print(0.1 + 0.2 == 0.3) # False!
# Here's what's actually happening
print(0.1 + 0.2) # 0.30000000000000004
When Precision Matters Most
Financial calculations are the classic example where this bites people. If you're working on a banking app at PythonSkillset, never store currency in floats. One day, your app will show someone owing $0.30000000000000004 in interest.
Instead, use Python's decimal module for money:
from decimal import Decimal
price = Decimal('19.99')
tax = Decimal('1.60')
total = price + tax
print(total) # 21.39, exactly what you expect
Notice we used strings in the Decimal constructor - that's important. If you pass Decimal(19.99), you're already passing a float with rounding errors.
Practical Workarounds
For most scientific computing needs, the built-in float is perfectly fine. The errors are tiny - typically less than 1 part in 10^15. But when you need to compare floats, never use ==. Instead, check if they're close enough:
import math
a = 0.1 + 0.2
b = 0.3
print(math.isclose(a, b)) # True
You can also set tolerance levels with math.isclose:
print(math.isclose(a, b, rel_tol=1e-9)) # relative tolerance
print(math.isclose(a, b, abs_tol=1e-12)) # absolute tolerance
What About Very Large or Very Small Numbers?
Python floats can represent numbers from about 10^-308 to 10^308. Outside that range, you get special values:
- inf for infinity (overflow)
- -inf for negative infinity
- nan for "not a number" (when math doesn't make sense)
print(1e308 * 10) # inf
print(1e-308 / 10) # 0.0 (underflow)
print(float('nan') + 5) # nan
The Decimal Module's Hidden Cost
While Decimal solves precision issues, it's about 10-20 times slower than native floats. So for data science or graphics work, stick with floats. For financial calculations or any case where exact decimal representation matters, pay the performance cost and use Decimal.
A Real-World Lesson
At PythonSkillset, we once had a user who couldn't figure out why their physics simulation gave inconsistent results after running for an hour. They were comparing positions with == instead of checking if positions were close enough. Over time, tiny floating-point errors accumulated, and their simulation "broke." The fix was simple - use tolerance-based comparisons.
The Bottom Line
Python's floating-point math isn't buggy - it's doing exactly what the IEEE 754 standard says it should. Understand its limitations, use Decimal when precision is critical, compare with tolerance, and you'll avoid the traps that catch most developers.
That unexpected 0.30000000000000004 isn't a bug. It's a reminder that computers think in binary, but we live in a decimal world.
Comments
Questions, corrections, and tips stay visible for everyone reading this page.
Join the discussion
No comments yet
Be the first to leave a note — it helps the next reader.