Software
Why a computer insists that a tenth plus two tenths is not three tenths
Some perfectly ordinary decimal fractions have no exact representation in binary, and the arithmetic that follows inherits that gap forever.

This works through floating point arithmetic in the order the parts actually depend on each other.
The short version
- A tenth is a repeating fraction in binary, exactly as a third is in decimal.
- Floating point trades exactness for an enormous range of magnitudes.
- Errors accumulate, so the order of operations changes the result.
Binary cannot write a tenth exactly
In decimal, a third has no exact written form and becomes a repeating expansion that must be cut off somewhere. In binary, the same fate befalls a tenth, because ten is not a power of two and the expansion never terminates. A computer therefore stores the nearest value it can represent, which is extremely close to a tenth but not equal to it.
Adding two such approximations produces a value near three tenths, and it is not the nearest representation of three tenths either. The comparison then fails, and the machine is behaving exactly as specified while appearing to contradict basic arithmetic.
What floating point is actually trading
Numbers are stored as a fixed number of significant digits together with an exponent describing where the point sits. That structure allows a single format to express both astronomically large and vanishingly small quantities without changing type.
Under load, the price is that the gap between representable values grows with magnitude, so precision is relative rather than absolute. Near zero the representable values are packed tightly, while at large magnitudes the gaps between them become enormous. Adding a small number to a very large one can therefore change nothing at all, because the result rounds back to where it started.
Errors accumulate and order matters
Every operation rounds its result, and repeated rounding in a long calculation compounds in ways that are hard to predict. Adding a long list of numbers from smallest to largest gives a different answer than adding them in the reverse order. Subtracting two nearly equal numbers is the classic disaster, because the leading digits cancel and only the uncertain trailing ones remain.
Mechanically, numerical libraries reorder operations specifically to avoid these situations, which is why they exist rather than being written afresh. This is also why identical calculations on different hardware or compilers can produce results that differ in the last digits.
Comparing for equality is the reliable bug
Testing whether two computed values are exactly equal almost always fails eventually, because rounding took them to neighbouring representations. The usual remedy is testing whether the difference is smaller than a chosen tolerance rather than testing for exact equality.
Choosing that tolerance is genuinely difficult, since an appropriate margin for small values is meaningless for very large ones. Loops that count by adding a fractional step accumulate error and may run one iteration too many or too few.
Counting with whole numbers and multiplying to obtain the fractional value avoids the accumulation entirely.
Money is stored differently for exactly this reason
Financial calculations require decimal fractions to behave exactly, since a rounding difference is a real discrepancy in an account. The common solution is to store amounts as whole numbers of the smallest unit and handle the decimal point at display time. Some languages and databases provide decimal types that represent base ten fractions exactly at the cost of speed.
The short version: rounding rules also matter, and different jurisdictions and contexts specify different behaviour at the halfway point. A system that mixes binary floating point with monetary values will eventually produce a total that does not match its parts.
Implementations differ, and vendors are not obliged to document the differences.
Where it shows up in ordinary use
Spreadsheets display rounded values while calculating with the full stored representation, so a visible total can disagree with visible rows. Graphics and simulation accumulate positions over many steps, and small errors become visible drift or jitter over time. Very large identifiers stored as floating point silently lose their last digits, which corrupts data in ways nothing detects.
Under load, serialising a value to text and reading it back can change it unless enough digits are written to round-trip exactly. None of this is a defect in any particular language, because they nearly all use the same underlying hardware representation.
The takeaway
The machine is not confused about arithmetic; it is telling you what fits in binary.
Once you know what it is trading away, the design stops looking arbitrary.
Questions readers ask
Is this a bug that will be fixed?
No. It is a consequence of representing decimal fractions in binary with finite storage. The behaviour is standardised and deliberate.
Should I always use decimal types instead?
Only where exact decimal behaviour matters, such as money. They are slower, and for scientific work binary floating point is the right tool.
Also by Junko Ishida
- USB-C solved the connector and not the confusionPower & Batteries
- File formats decide whether your files outlive the softwareSoftware
- Where the electricity goes when everything is switched offPower & Batteries
- The memory effect was real, and it has nothing to do with your phonePower & Batteries





