The most famous bug that is not a bug
Run the block below before reading further. Really. It is one line of math that surprises almost everyone the first time.
Code exercise · python
Run this and look closely at the output.
Why this happens
Remember lesson 2-1: everything is bits, so decimals must be stored in binary too. Here is the catch. In decimal, 1/3 has no exact form: 0.3333... forever. In binary, 1/10 has the same problem. There is no finite pattern of bits that equals exactly 0.1, so the computer stores the closest possible value, which is 0.100000000000000005551...
The standard for this is called floating point (the float type, 64 bits per number). It gives about 15-16 reliable decimal digits, and every calculation may pick up a microscopic rounding error.
So 0.1 + 0.2 adds two already-slightly-wrong numbers and lands on 0.30000000000000004. Nothing is broken. This happens in every language, on every computer, because they all share the same binary format (IEEE 754).
What to do about it
Three standard tools, from most common to most exact:
- Never compare floats with ==. Compare rounded values or use
math.isclose. - For money, use integers: count cents, not dollars. 19.99 dollars is the integer 1999. Integers in binary are exact.
- For decimal-exact math (finance, billing), use the
decimalmodule, which stores digits the way humans write them, at the cost of speed.
Try all three below.
Code exercise · python
Run this. It shows the three fixes: rounding before comparing, math.isclose, and the decimal module.
Code exercise · python
Your turn: fix a money bug. Three items cost 10 cents each. The float version prints an ugly total. Compute the total in integer cents, then print it as dollars using an f-string. Target output line 2: $0.30
Quiz
A teammate says "0.1 + 0.2 != 0.3 is a Python bug, let's switch to JavaScript." What is wrong with that plan?