TOOLTIKI Lovable tool, really free

Why 0.1 plus 0.2 is not 0.3

Add 0.1 and 0.2 in almost any programming language and the answer is 0.30000000000000004. Nothing is broken and no rounding error has crept in — the two values being added were never exactly a tenth and two tenths in the first place.

A tenth in binary is a recurring fraction, exactly as a third in decimal is. Writing it down in a fixed number of digits means cutting it off somewhere, and the answer carries the leftovers.

Why can binary not hold a tenth?

Because a fraction terminates in a base only when its denominator divides a power of that base. Decimal handles halves, quarters, fifths and tenths cleanly because ten is two times five. Binary has only twos, so anything with a factor of five in the denominator recurs.

A tenth in binary is 0.000110011001100… repeating forever. Stored in a fixed number of bits it becomes a value slightly above or below a tenth, and the arithmetic that follows is exact arithmetic on those slightly wrong values.

The result is not random. The same calculation gives the same answer every time on every conforming system, which is why the specific figure is so well known.

How much precision is there?

Around fifteen to seventeen significant decimal digits for the usual double-precision format, which stores a sign, an exponent, and a fixed budget of significand bits.

Value Stored as
0.5, 0.25, 0.75 exactly
0.1, 0.2, 0.3 approximately
Integers up to about 9 quadrillion exactly
Larger integers approximately

The first row is why some decimal arithmetic behaves perfectly. Anything whose fractional part is a sum of halves, quarters and eighths is exact, so tests written with 0.5 pass and tests written with 0.1 do not.

The integer limit is the one that silently corrupts data, as the JSON article covers. An identifier longer than about sixteen digits comes back with its last digits changed.

How should you compare two of them?

With a tolerance rather than with equality. Two values that should be the same can differ in the last bit, so an exact comparison reports them as different and is technically correct.

The tolerance has to suit the magnitude. A fixed small difference works for numbers near one and is meaningless for numbers in the millions, where the gap between representable values is itself larger than that tolerance.

The practical approach is to compare the relative difference for large values and an absolute one near zero. Any comparison of computed decimals for exact equality is a bug waiting for the right input.

What should money be stored as?

Whole numbers of the smallest unit. Storing an amount in cents or pence as an integer removes the problem entirely, because integers are exact within the range that matters and every operation stays exact.

Rounding then becomes an explicit decision at the point of display or at the point of a transaction, which is where it belongs. Accumulating fractional values and rounding at the end produces totals that disagree with the sum of their rounded parts.

That disagreement is the one that gets noticed, because a column of figures that does not add up to its own total is the first thing anyone checks.

What else behaves oddly?

A few values with no ordinary equivalent. The result of an undefined operation is a special value that is not equal to itself, so comparing it to anything including a copy of itself returns false — which is how you test for it.

There are two zeros, a positive and a negative, which compare as equal and behave differently when divided into. There are infinities at both ends, produced by overflow rather than only by dividing by zero.

None of these is a defect. They are defined behaviours in a standard that has to represent the results of every operation, including the ones that have no answer.

Does the order of operations change the result?

Yes, which is the property that most surprises people. Floating point addition is not associative — adding a list of numbers in a different order can give a different total, because each intermediate result is rounded.

It matters most when the magnitudes differ widely. Adding a very small number to a very large one can change nothing at all, since the result rounds back to the large number, and a thousand such additions still change nothing while the same thousand added together first would.

The practical guidance for summing a long list is to add the smallest values first, or to use a compensated summation that tracks the lost part. For a short list of similar values it makes no difference worth chasing.

Questions people ask

Do other languages avoid this? Only by using a different type. Any language using the same binary format gets the same answers.

Is a decimal type the answer? For money, often. It is slower and it represents decimal fractions exactly.

Why does printing sometimes hide it? Display rounds to a readable number of digits, so the stored value and the shown value differ.

Does rounding fix it? It fixes the display. The stored value is unchanged, so the next calculation starts from the same place.

Keep the exactness where it matters. The rounding calculator shows what each rounding rule does to a value, the fraction calculator works in exact ratios rather than decimals, and the scientific notation converter makes the number of significant digits explicit.