Floating Point Precision: Why 0.1 + 0.2 Is Not 0.3

- Floating point precision errors come from binary representation: 0.1 has no finite binary form, so the stored value is off by ~10⁻¹⁷, and adding two of these slightly-off values makes the error visible.
- Never compare floats with
==: useabs(a - b) < 1e-9instead; two different computation paths to the same mathematical value can produce different bit patterns and fail equality. - Float hash map keys are a silent bug:
0.1 + 0.2and0.3have different bit patterns and hash to different buckets even though they look equal. - Binary search on real numbers must use a fixed iteration count (100 halvings), not a convergence condition; near a boundary,
(lo + hi) / 2can equalloorhiand loop forever. sqrt()andlog()are O(1) operations: the variable complexity comes from how many times you call them, not from the arithmetic itself.- Catastrophic cancellation destroys all significant digits when subtracting two nearly-equal floats; geometry problems with near-coincident points are the main coding interview trap.
- Prefer integer reformulations:
dx² + dy² == r²instead ofsqrt(dx² + dy²) == r; integer arithmetic is exact until overflow and sidesteps float comparison entirely.
Three lines that have derailed more interviews than almost anything else:
>>> 0.1 + 0.2 0.30000000000000004 >>> 0.1 + 0.2 == 0.3 False
Not a Python bug. Not JavaScript being weird again. This one belongs to every language, every platform, every computer ever built. It is IEEE 754 floating point, and it has been quietly wrong since 1985. Misunderstanding it will break code you are confident is correct, including code you write under interview pressure.
Short answer: floating point breaks because computers store numbers in binary. Most decimal fractions have no finite binary representation, so the computer stores the closest value that fits in the available bits. Tiny errors compound. Equality comparisons fail silently. Here is why it happens and what to do about it.
Binary Cannot Write 0.1
Think about writing 1/3 in decimal. You get 0.333... and it never terminates. No matter how many digits you write, you cannot express it exactly.
The same problem appears in binary with 0.1. In binary, 0.1 is the repeating fraction 0.0001100110011001100110011..., running forever. A computer cannot store infinity, so it rounds to the nearest value that fits in 52 bits of mantissa.
The value actually stored when you type 0.1 is:
0.1000000000000000055511151231257827021181583404541015625
That looks harmless. Add two of these slightly-off values and the accumulated error becomes visible. 0.1 + 0.2 returns 0.30000000000000004, not 0.3. The moment you first discover this, there are two types of engineers: ones who say "huh, interesting" and move on, and ones who spend the next hour questioning everything they thought they knew about addition.

Every programmer, every time, forever.
What Lives Inside Those 64 Bits
IEEE 754 double precision is the standard your language uses for floating point. Every float in Python, every double in Java, C, or C++, and every number in JavaScript follows this layout:
| Part | Bits | Purpose |
|---|---|---|
| Sign | 1 | Positive or negative |
| Exponent | 11 | Powers of 2 |
| Mantissa | 52 | The significant digits |
The value is: (-1)^sign × 2^(exponent - 1023) × 1.mantissa
The 52-bit mantissa gives you roughly 15 to 17 significant decimal digits. Values like 0.1 are stored with an error around 10^-17. Usually invisible. Sometimes not.
For single precision (C's float, Java's float), precision drops to about 7 significant digits, roughly a billion times worse. If you ever see float in production financial code, that is a bug. Someone at that company is explaining a $0.000002 discrepancy to their finance team right now.
The Patterns That Bite You in Interviews
Never Compare Floats with ==
The most common mistake. It shows up in loops, binary search termination, geometry checks, and also in that interview answer where you were this close to a hire signal before silently returning the wrong answer.
# Will silently miss the target for x in nums: if x == target: return True
Use an epsilon comparison instead:
EPSILON = 1e-9 for x in nums: if abs(x - target) < EPSILON: return True
What epsilon? For most interview problems, 1e-9 is fine. If the problem specifies a tolerance like "answer within 10^-5", use half that value.
The same trap catches hash lookups. Two floats that represent the same mathematical value can have different bit patterns if they were computed by different paths, so they hash to different buckets. Your beautiful hash map lookup silently returns nothing. No error. Just vibes.
d = {} d[0.1 + 0.2] = "computed" d[0.3] # KeyError. Different bits, different hash.
Never use raw floats as dictionary keys or set elements. If you need float keys, round to a fixed number of decimal places first, then store as a string or scaled integer.
Your Loop Might Run 11 Times. Or 9. Good Luck.
total = 0.0 count = 0 while total < 1.0: total += 0.1 count += 1 # How many iterations?
You'd expect 10. You might get 10 or 11. Each addition compounds the rounding error slightly differently, and the final value of total can land just above or just below 1.0. The loop does not care about your expectations.
Never drive a loop with a float accumulator. Use integer counts:
for _ in range(10): total += 0.1
Same intent, no surprise termination.
Binary Search on Reals Will Loop Forever Without This Fix
Binary search over a floating-point range is a legitimate interview pattern. You see it on problems like "find the minimum real value x where f(x) >= target." The naive version has a trap:
def binary_search_real(lo, hi, check): while lo < hi: # Can loop forever near a boundary mid = (lo + hi) / 2 if check(mid): hi = mid else: lo = mid return lo
Near the boundary, lo and hi can stop converging. The gap between adjacent representable floats means (lo + hi) / 2 can equal lo or hi exactly, and the loop never terminates. The interviewer is watching. The clock is ticking.
The robust fix is a fixed iteration count. 100 halvings gives you far more precision than any interview problem asks for:
def binary_search_real(lo, hi, check): for _ in range(100): mid = (lo + hi) / 2 if check(mid): hi = mid else: lo = mid return lo
See the binary search invariant guide for the broader framework this fits into.
Subtraction Can Delete All Your Precision
Subtracting two nearly-equal floats destroys precision:
a = 1.0000000000000002 # 1 + 2 × 10^-16 b = 1.0000000000000000 # 1 + 0 a - b # Should be 2 × 10^-16. Actually returns 0.0.
Both values round to the same 64-bit representation, so their difference is zero. All significant digits disappear. This is catastrophic cancellation and it is not subtle when it happens.
In interview geometry problems, this means collinearity tests and distance comparisons can silently give wrong answers when points are nearly coincident. This is why most interview geometry problems specify integer coordinates. If a geometry problem hands you floats, flag it and add an epsilon tolerance to every comparison.
That sqrt() Call Costs Nothing
When you call sqrt(n) or log(n) inside an algorithm, these do not add a complexity factor. Modern CPUs have dedicated floating-point units with hardware instructions for these functions. They run in constant time regardless of n.
This matters when explaining complexity at the whiteboard:
- Finding all divisors of n: O(√n) because you loop from 1 to √n. The
sqrt()call is O(1). The loop that runs √n times is what costs. - Binary search: O(log n) because you do log n iterations. The
log()function call is O(1).
The variable cost is iteration count, not the arithmetic function call. You may have said "I should cache sqrt(n) to avoid the expensive call" in an interview once. The interviewer wrote something down. Cache it if it improves readability, not for performance.
Avoid the Float Entirely
The cleanest fix for most interview scenarios is to avoid floats completely. Integer arithmetic in computers is exact until overflow (see the integer overflow guide for that side of the coin).
For problems involving distance checks, skip the square root:
# Risky: sqrt introduces float error if sqrt(dx**2 + dy**2) == r: ... # Safe: integer equality, exact if dx**2 + dy**2 == r**2: ...
For problems involving monetary values, store cents not dollars. You will learn this lesson one way or another. For fractions, store numerator and denominator as separate integers.
Almost every "is this computed value equal to X" check involving a float can be reformulated as an integer equality check. This reformulation takes ten seconds to write. It saves you from a 45-minute debugging session where the code looks correct, the tests pass, and the answer is wrong by 0.000000000000004.

Floating point errors respect neither interviews nor pizza orders.
When you spot the integer reformulation in an interview, say it out loud. It signals that you understand the underlying issue, not just the surface symptom.
When You Actually Need Exact Decimals
Python's decimal module and Java's BigDecimal give you exact decimal arithmetic at a performance cost:
from decimal import Decimal Decimal('0.1') + Decimal('0.2') == Decimal('0.3') # True
The string initialization matters. Decimal(0.1) captures the already-imprecise float. Decimal('0.1') parses the string and gets it right.
In interviews, you will almost never need Decimal. It exists for financial software that genuinely cannot tolerate rounding. If an interview problem involves money, the input will typically already be integers representing the smallest denomination.
Five Rules. Commit Them. Don't Debug This Twice.
- Never compare computed floats with
==. Useabs(a - b) < epsilonwhere epsilon is 1e-9 unless the problem says otherwise. - Never use floats as hash map keys or set elements. Round to integers or strings first.
- Float loop conditions can terminate early, late, or never. Drive loops with integer counts.
- Binary search on reals: use a fixed iteration count (100 halvings), not a convergence condition.
sqrt(n)andlog(n)are O(1) operations. The complexity lives in how many times you call them, not the call itself.
Most interview problems sidestep floating point by using integer inputs. When floats appear, the interviewer usually wants to see you recognize the comparison hazard and handle it. That is the whole test. Recognizing it, naming it, and fixing it in 30 seconds is exactly the signal they are looking for.
If you want to practice these edge cases under actual interview pressure, SpaceComplexity runs voice-based mock interviews where float traps show up in binary search and geometry problems, with rubric feedback on whether you caught them.
Further Reading
- What Every Computer Scientist Should Know About Floating-Point Arithmetic, Goldberg 1991, the canonical reference on the subject
- Floating-point arithmetic, Python 3 documentation, Python's own explanation with concrete examples
- IEEE 754, Wikipedia, the standard itself, readable overview with the bit layout
- Double-precision floating-point format, Wikipedia, detailed breakdown of the 64-bit format
- Catastrophic cancellation, Wikipedia, the subtraction problem with worked examples