An equality check on decimal numbers fails even though the maths is clearly right.
0.1 + 0.2 == 0.3 prints False. A list of probabilities sums to
0.9999999999999999 instead of 1.0, so an assert total == 1.0 kills the
pipeline — or worse, an if total == 1.0 silently takes the wrong branch and
nothing crashes at all.
First weeks of numeric code: validating that probabilities sum to 1, splitting a bill or a dataset by percentages, comparing a computed score against a threshold written as a decimal literal. Very common in test assertions that compare float results exactly. Linked module: 0.7 (The maths you will actually use).
Computers store numbers in binary, and 0.1 in binary is a repeating fraction —
like 1/3 in decimal, it never terminates. So the machine stores the nearest value
it can hold, which is very slightly off. Each arithmetic step can add another
tiny rounding error, and == compares exact bit patterns, so "close enough" is
not equal. Confirm it yourself: print(f"{0.1 + 0.2:.20f}") shows
0.30000000000000004441 — the error was always there, hidden by friendly
printing. This is IEEE-754 float behaviour in every language (C, Java,
JavaScript, NumPy), not a Python bug, so switching tools will not save you.
Stop comparing computed floats with ==. Use a tolerance: math.isclose(a, b)
for plain Python, np.isclose(a, b) per element or np.allclose(a, b) for whole
arrays. For a probability total, test abs(total - 1.0) < 1e-9 instead of
equality. For money, never use floats at all: hold amounts in integer paise (or
decimal.Decimal) so every sum is exact. If a test asserts float equality, change
the assertion to pytest.approx or isclose — do not round the code to satisfy
the test.
Adopt the rule: == is for integers and strings; floats get isclose. In code
review, flag any == between computed floats as a bug waiting for a dataset.
When a float looks suspicious, print it with :.20f before theorising. Keep
money in integers from day one — the habit costs nothing and audits love it.
Q: "Why does 0.1 + 0.2 == 0.3 print False, and what do you do about it in
production code?" Strong answer: binary cannot represent 0.1 exactly, so stored
values are rounded and errors accumulate; == checks exact bits; the fix is
tolerance-based comparison (isclose / allclose) and integer units for money.
Naming the :.20f trick to reveal the hidden digits signals real debugging
experience, not a memorised fact.