Floating-Point Numbers: Why 0.1 + 0.2 Isn't Exactly 0.3
Open a browser console, a Python shell or almost any programming language, and type:
0.1 + 0.2
You'll get 0.30000000000000004.
It looks like a bug. It isn't. Your computer is doing exactly what the international floating-point standard says it should. The real cause is simple: in binary, 0.1 can't be written exactly, any more than 1/3 can be written exactly in decimal.
0.1 Is Harder for a Computer Than 0.5 or 0.125
We think of 0.1 as a "nice, round" number. It is, in base 10. But computers store fractions in base 2, where the only fractions that end are those whose denominators are powers of 2:
0.5 = 1/2 = 0.1₂ (exact)
0.25 = 1/4 = 0.01₂ (exact)
0.125 = 1/8 = 0.001₂ (exact)
0.1 = 1/10 = 0.000110011001100110011…₂ (repeats forever)
Since 10 = 2 × 5, and 5 isn't a power of 2, one-tenth becomes a repeating binary fraction. A computer must cut it off somewhere, so it stores a value that's very close to 0.1, but not equal to it.
What Actually Gets Stored
A standard 64-bit double follows the IEEE 754 standard: 1 sign bit, 11 exponent bits, 52 fraction bits. The closest double to 0.1 is exactly:
0.1000000000000000055511151231257827021181583404541015625
It's a tiny bit more than 0.1. The stored value of 0.2 is also slightly high. When you add them, the tiny errors combine, and the result is rounded to the nearest representable double:
0.3000000000000000444089209850062616169452667236328125
But the closest double to 0.3 is a different value, slightly below 0.3. The two don't match, so:
0.1 + 0.2 == 0.3 → false
Programming languages print the shortest decimal that identifies the stored value uniquely, which is why you see 0.30000000000000004.
How Precise Is a Double?
A 64-bit double gives about 15 to 17 significant decimal digits. The smallest gap near 1.0, called machine epsilon, is:
2⁻⁵² ≈ 2.22 × 10⁻¹⁶
That's extraordinarily precise for measurements. The problem isn't lack of precision. It's that decimal fractions we care about, like prices, aren't exactly representable at all. See binary place values with the binary to decimal converter.
When Tiny Errors Cause Big Problems
The Patriot Missile (1991)
On February 25, 1991, during the Gulf War, a U.S. Patriot missile battery in Dhahran, Saudi Arabia, failed to intercept an incoming Scud missile. The Scud struck a barracks and killed 28 American soldiers.
A U.S. General Accounting Office report traced the failure to timekeeping. The system counted time in tenths of a second, and multiplied by 1/10 stored in a 24-bit fixed-point register. The chopped binary value was off by about 0.000000095 per tenth of a second.
The battery had been running for about 100 hours. The error had accumulated to roughly 0.34 seconds. A Scud travels about 1,676 meters per second, so the system looked in the wrong place, by more than half a kilometer.
The Vancouver Stock Exchange (1982–1983)
The Vancouver Stock Exchange launched a new index in January 1982 at a value of 1,000. It was recalculated thousands of times a day, and each time the result was truncated to three decimal places instead of rounded. By November 1983, the index had fallen to around 520, while the market itself hadn't. Recalculated correctly, the index was about 1,098.
An Insider Reference: William Kahan and IEEE 754
Before 1985, different computer manufacturers handled fractional numbers in different ways. The same program could give different answers on different machines.
William Kahan, a mathematician at the University of California, Berkeley, led the design of the IEEE 754 standard, adopted in 1985. It defined how floating-point numbers are stored, rounded, and what happens with special cases like division by zero (±∞) and invalid operations (NaN). Kahan received the 1989 Turing Award for his work on numerical analysis. Nearly every CPU made today implements IEEE 754.
How to Handle Floating Point Correctly
1. Never compare floats with ==. Compare with a tolerance:
abs(a - b) < 1e-9
Many languages provide helpers, such as Python's math.isclose().
2. Store money as integers. Use cents: $19.99 becomes 1999. Or use a decimal type designed for base-10 arithmetic, like Python's decimal.Decimal or Java's BigDecimal.
3. Round only for display. Keep full precision during calculations, and format at the end.
4. Watch accumulating errors. Adding 0.1 ten thousand times drifts from 1,000. Where possible, compute from integers (i × 0.1) rather than repeatedly adding.
5. Mind the order of operations. Adding numbers of very different sizes can lose the small one entirely: 1e16 + 1 == 1e16 in doubles.
Two Concepts Worth Knowing
Scientific Notation in Binary
Floating point stores numbers as significand × 2^exponent, just like scientific notation uses powers of 10. The exponent lets the same 64 bits represent both 10⁻³⁰⁰ and 10³⁰⁰, at the cost of exactness.
Rounding Error
Rounding error is the difference between a true value and its stored approximation. Individually tiny, rounding errors can grow through repeated operations, as the Patriot and Vancouver cases show.
Quick Answer: Why Does 0.1 + 0.2 Not Equal 0.3?
Computers store decimals in binary, and 0.1 and 0.2 become infinitely repeating binary fractions. They're rounded to the nearest 64-bit floating-point values, which are slightly off. Adding them gives 0.30000000000000004, which isn't the stored value for 0.3. Compare floats with a tolerance and store money as integers.
Try Them Yourself
- Binary to Decimal Converter: see which fractions binary can represent exactly
- Binary to Hexadecimal Converter: inspect a double's raw bits
- Table of Bases: compare number systems
- Scientific Calculator: experiment with repeated additions
- Division Tables: find fractions that repeat in decimal too
- How Computers Represent Numbers: integers, overflow and IEEE 754
In your favorite language, add 0.1 to a variable ten times and print it with 20 decimal places. Then do the same with integers and divide by 10 at the end. The difference is the lesson.