backend / python core / tricky questions / 17_floats_and_equality.md

Floats and equality

1 min read source

Floats and equality

The gotcha

0.1 + 0.2 != 0.3. IEEE 754 double-precision floats can’t represent most decimal fractions exactly. Equality comparison fails for values that “should” be equal.

Minimal repro

0.1 + 0.2          # 0.30000000000000004
0.1 + 0.2 == 0.3   # False

# Underlying:
from decimal import Decimal
Decimal(0.1)
# Decimal('0.1000000000000000055511151231257827021181583404541015625')

The literal 0.1 is not the rational 1/10 — it’s the nearest representable double. Same for 0.2 and 0.3. The closest doubles to 0.1 and 0.2 add up to a number whose closest double is not the closest double to 0.3.

Why it happens

Floats use a binary radix. 0.1 decimal has no terminating binary representation (like 1/3 has no terminating decimal). The runtime stores 53 bits of mantissa, which is the closest possible — but rounding errors accumulate across operations.

Special values to know:

  • float("inf"), float("-inf"), float("nan") — finite arithmetic doesn’t always behave: nan != nan is True.
  • 0.0 == -0.0 is True but 1/0.0 raises and 1/-0.0 raises (in Python; in C they’d be ±inf).
  • True / 0 raises ZeroDivisionError.

How to avoid

For tolerant equality:

import math
math.isclose(0.1 + 0.2, 0.3)              # True
math.isclose(a, b, rel_tol=1e-9, abs_tol=0.0)

For exact decimal arithmetic (money, etc.), use Decimal:

from decimal import Decimal, getcontext
Decimal("0.1") + Decimal("0.2") == Decimal("0.3")   # True

Pass strings to Decimal, not floats — Decimal(0.1) inherits the float’s imprecision.

For NaN-safety:

import math
math.isnan(x)              # only correct way to test for NaN

Interview angle

“What does 0.1 + 0.2 == 0.3 evaluate to, and why?” Follow-up: “How would you compare two floats safely?” Bonus: “Is nan == nan True?” (No — IEEE 754 says NaN is not equal to anything, including itself.)