0.1 is stored as 0.1000000000000000055511151231257827021181583404541015625. Not approximately — exactly. A double is a rational number with a power of two on the bottom, so its decimal expansion terminates, and this is the whole of it. That is why 0.1 + 0.2 is 0.30000000000000004.
Why the expansion terminates
A double is not an approximation of a real number in the vague sense. It is a specific rational number: a 53-bit integer times a power of two.
Because the only prime in the denominator is two, the decimal expansion always ends. Multiplying by 2⁻⁶ is the same as multiplying by 5⁶ and moving the decimal point k places, and both of those are finite operations.
So the exact value can be written out in full — and it is worth seeing, because the numbers are longer than people expect. The double nearest 0.1 has 55 decimal places.
The reverse is what causes the trouble. A tenth in binary is 0.0001100110011001100... repeating forever, exactly as a third in decimal is 0.333... forever. Base ten has 2 and 5 as its primes and can write a half and a fifth exactly; base two has only 2, and cannot write a fifth at all.
Why 0.1 + 0.2 fails
Three separate things go wrong, and the third is the one people miss.
0.1 is not stored as 0.1. The nearest double is slightly above it.
0.2 is not stored as 0.2 either. Also slightly above.
Their errors do not cancel. Adding the two stored values gives something slightly above the double nearest 0.3, so the comparison fails and the display shows 0.30000000000000004.
Nothing is broken. Every step is doing exactly what IEEE 754 specifies, on values that were never the ones you typed. The tool above lets you enter both numbers and see the exact stored values either side of the sum.
It is worth noticing that 0.1 + 0.2 is unusual only in being famous. Most decimal fractions have the same problem; that particular sum is simply the one where the display shows it.
What is exactly representable
Some numbers are stored perfectly. The rule is simple once stated.
Every integer up to 2⁵³ — about 9 quadrillion. Beyond that, consecutive integers start to share a representation.
Any fraction whose denominator is a power of two. A half, a quarter, an eighth, three sixteenths. These are exact.
Nothing else. A tenth, a third, a hundredth — none of them. Which is awkward, because those are exactly the numbers money is denominated in.
It is why financial software does not use doubles for currency. A cent is a hundredth, and a hundredth is not representable, so a long chain of additions drifts. Integer cents or a decimal type is the standard answer.
The gaps grow
Doubles are not evenly spaced. They are dense near zero and sparse a long way from it.
Between 1 and 2 the gap is about 2.2×10⁻¹⁶. Between 2 and 4 it is twice that. Every time the exponent increases, the spacing doubles.
So above 2⁵³ the gap exceeds 1, and adding 1 to such a number changes nothing at all. The addition happens, and the result is the original value.
That is why summing a long list of numbers loses accuracy when the running total grows large relative to the terms. Compensated summation — Kahan’s algorithm — exists precisely to track the part that keeps getting discarded.
This page reports the gap for whatever number you enter, so the effect is a number rather than a warning.
What to do about it
Four practical responses, depending on what the numbers are for.
Never compare with equality. Use |a − b| < tolerance, with a tolerance chosen for the scale of the numbers involved.
Use integers for money. Store cents, or paise, or the smallest unit. Integers are exact, and currency has a smallest unit by definition.
Use a decimal type when the base matters. Python’s decimal, Java’s BigDecimal and SQL’s NUMERIC all work in base ten, so a tenth is exact.
Use exact rationals when the question is yes or no. That is the approach taken across this site: on the linear algebra pages, on the shoelace area, on the line-intersection determinant. Anywhere the answer turns on whether something is exactly zero, floating point gives the wrong answer rather than an imprecise one.
Sources and methodology
The format and its consequences are standardised; these are the references.
Method. The exact value is computed with arbitrary-precision integers rather than printed from a double. A double is significand × 2^e, and multiplying by 2^−k is multiplying by 5^k and moving the decimal point k places — so the expansion terminates and can be produced in full. The suite verifies the claim rather than trusting it: every printed exact value is parsed back with Number() and required to give the identical double, which is what makes the word "exact" on this page checkable. That engine is verified on every change against 90 hand-written assertions, including that every exact decimal printed parses back to the identical double, and that 0.1 matches its full fifty-five digit expansion. The count and the per-case breakdown are published on the formula verification page.
Read the guide
Rounding rules interact with all of this — the Rounding Calculator covers why 1.005 does not round the way people expect.