IEEE-754 representation error and safe float comparison
Python floats are IEEE-754 binary64 doubles: a sign bit, 11 exponent bits and 52 mantissa bits. Numbers like 0.1 and 0.2 have no finite binary representation (like 1/3 in decimal), so each is stored as the nearest representable double. Adding them rounds again, producing 0.30000000000000004, which is a different double from the nearest one to 0.3. Python is not buggy here; every language using doubles behaves identically. repr() shows the shortest string that round-trips, which is why the long tail appears.
How I compare floats depends on the domain. For general numeric code, math.isclose(a, b, rel_tol=1e-9, abs_tol=0.0) (3.5+) is symmetric and scales with magnitude; always set abs_tol when either value may be near zero, because relative tolerance against 0 can never succeed. In tests I use pytest.approx. numpy.isclose has different semantics (asymmetric, default atol=1e-8), so do not assume the two agree. A hand-rolled abs(a - b) < 1e-9 is a common mistake because a fixed epsilon is too loose for tiny numbers and too strict for huge ones.
When not to use floats: money and anything requiring exact decimal results should use decimal.Decimal (constructed from strings, not floats - Decimal(0.1) captures the binary error) or integer minor units such as cents. For exact rational arithmetic use fractions.Fraction. For summing many floats, math.fsum or sorted/pairwise summation avoids accumulated error since float addition is not associative. Version note: since Python 3.12 the built-in sum() uses compensated summation for floats, so sum([0.1] * 10) returns 1.0 there but a plain += loop (or older versions) gives 0.9999999999999999.
Trade-offs: Decimal is exact for decimal fractions but 10-100x slower and still rounds on division; integers in cents are fast and exact but need care with percentages and rounding rules; floats are right for scientific and performance-critical work if you design for tolerance. Also note approximate equality is not transitive, so do not use it as a dictionary key or for deduplication without snapping values to a grid first.
0-2 years experience
2-5 years experience
5-8 years experience
8+ years experience