Skip to content

Web development

The Reason Floating-Point Math Quietly Lies to Your Code

by Roman10 Admin
The Reason Floating-Point Math Quietly Lies to Your Code

Open a console in almost any programming language and type a calculation as simple as adding a tenth and two tenths. You will very often get back not the clean three tenths you expect, but something like 0.30000000000000004. To a newcomer this looks like a bug, or a broken language, or a computer that cannot add. It is none of those things. It is floating-point arithmetic behaving exactly as designed, and the surprise it produces is one of the most fundamental and least understood facts in programming. Understanding why computers get decimals wrong — and when it matters and when it does not — is essential to writing code that handles numbers correctly, and to not being blindsided when the math quietly lies.

Why the computer cannot store your decimal

The root of the problem is a mismatch between how humans write numbers and how computers store them. We write in base ten, where numbers like a tenth are perfectly ordinary. Computers store numbers in binary, base two, and the trouble is that many numbers that are simple and exact in base ten cannot be represented exactly in base two. A tenth, in binary, is a repeating fraction that goes on forever, exactly as a third does in our familiar decimal notation. Since a computer has only a finite amount of space to store a number, it cannot hold that infinite representation; it has to round it off to the nearest value it can represent.

This is the whole mystery, and it is not a flaw but a consequence of finite storage. When you write a tenth, the computer stores the closest binary approximation it can fit, which is very slightly off. Do arithmetic with several such approximations, and the tiny errors combine, producing results that are close to the expected value but not exactly equal to it. The computer is not making a mistake; it is faithfully doing arithmetic on the approximations it was forced to store. The "wrong" answer is the accumulated residue of numbers that could never be held exactly in the first place. Floating point is a system for representing an infinite range of real numbers in finite space, and the price of that generality is that most decimals are approximations.

The bug that is not a bug

The practical face of this is the classic surprise: adding a tenth and two tenths does not yield exactly three tenths, and comparing the result to three tenths for equality returns false. Countless developers have stared at this in disbelief, convinced something is broken. Nothing is. The two approximate values were added, producing another approximate value that differs from the approximation of three tenths by a vanishingly small amount — but "vanishingly small" is not "zero," and an exact equality check notices the difference.

This is why one of the most important rules in working with floating point is to never compare floating-point numbers for exact equality. Two calculations that should mathematically produce the same result may produce values that differ in the last tiny digits, and testing them for exact equality will report them as different. The correct approach is to check whether two floating-point numbers are close enough — within a small tolerance — rather than exactly equal. Developers who do not know this write comparisons that fail intermittently and inexplicably, chasing a bug that is really just a misunderstanding of how the numbers work. The behaviour is not a defect to be fixed but a property to be accommodated.

When it matters and when it does not

A sense of proportion is essential here, because floating point's imprecision is genuinely irrelevant most of the time and genuinely dangerous some of the time. For a great deal of computing — graphics, physics simulations, scientific calculation, machine learning — floating point is exactly the right tool, and its tiny approximation errors are utterly negligible against the scale of what is being computed. In these domains, the ability to represent an enormous range of magnitudes matters far more than perfect decimal precision, and the small errors wash out. Worrying about them would be a mistake.

Where floating point becomes dangerous is anywhere that requires exact decimal values, and the canonical example is money. Financial calculations demand precision to the cent, and the tiny errors of floating point, accumulated across many operations, can produce results that are wrong by small but unacceptable amounts — a rounding discrepancy that should never exist in an account balance. Using floating point for currency is a classic and serious error, because the very imprecision that is harmless in a physics simulation is intolerable in a ledger. Knowing which category a given calculation falls into — the tolerant domains where floating point excels, or the exact domains where it must not be used — is the practical heart of handling numbers correctly.

The right tools for exact numbers

For the situations where floating point's approximations are unacceptable, the solution is not to fight floating point but to use a different kind of number entirely. When exact decimal values are required, most languages and platforms provide decimal types or arbitrary-precision arithmetic designed precisely for this purpose, which represent numbers in a way that avoids the binary-fraction problem and preserves exact decimal values. These are the correct tools for money and for any calculation where precision to a specific number of decimal places is non-negotiable.

There is a trade-off, which is why floating point remains the default: these exact types are generally slower and more limited in range than floating point, which is why floating point is used for the vast bulk of numeric computing where its speed and range matter and its imprecision does not. The skill is to reach for the exact tools specifically where exactness is required, and to use floating point everywhere else. A common technique for money, where a decimal type is unavailable, is to work in the smallest unit — storing amounts as whole numbers of cents rather than fractional units of currency — sidestepping the fractional imprecision entirely. The general principle is that the type of number you choose should match the precision the problem demands, rather than defaulting to floating point out of habit.

The literacy that prevents whole classes of bugs

Understanding floating point is a kind of literacy that quietly prevents entire categories of bugs, and its absence produces errors that are notoriously hard to diagnose. A developer who does not know why a tenth plus two tenths is not exactly three tenths will write equality comparisons that fail unpredictably, will use floating point for money and produce subtle financial errors, and will be baffled by results that are almost but not quite right. These bugs are especially insidious because the code looks correct and works most of the time, failing only in the specific cases where the accumulated imprecision crosses a threshold.

A developer who does understand it avoids all of this almost automatically. They compare with tolerance rather than exact equality, they reach for exact types when handling money or other precision-critical values, and they are never surprised by a result that differs in the last few digits, because they know why. This understanding costs nothing but a little study and pays off for an entire career, because floating point is everywhere and its surprises are perennial. It is one of those foundational pieces of knowledge that separates code that handles numbers reliably from code that harbours quiet, intermittent numerical bugs waiting for the wrong input.

Conclusion

Floating-point math quietly lies to your code for a reason rooted in the nature of computers: numbers that are simple in base ten, like a tenth, cannot be stored exactly in binary, so they are approximated, and those approximations produce results that are close to but not exactly what you expect. This is not a bug but a fundamental property, and it dictates a set of practices — never comparing floating-point values for exact equality, but checking whether they are close enough. The imprecision is negligible in the many domains where floating point excels, and dangerous in the ones, above all money, that demand exact decimal values, for which dedicated decimal or arbitrary-precision types are the right tools. Understanding all of this is a small piece of literacy that prevents a whole class of intermittent, hard-to-find numerical bugs. The computer is not bad at arithmetic. It is doing exactly what it was designed to do with the approximations it was forced to store — and knowing that is what lets you handle numbers correctly rather than being surprised when the math does not add up.

Related notes

More from this category

A Field Guide to Bad Names in Code
Web developmentAugust 17, 2026

A Field Guide to Bad Names in Code

There is an old joke that there are only two hard problems in computer science: cache invalidation, naming things, and off-by-one errors. The joke endures because the middle item…

by Mirel Thorne
The Time Zone Bugs That Break Software Twice a Year
Web developmentJuly 28, 2026

The Time Zone Bugs That Break Software Twice a Year

Every engineer meets it eventually. A system that ran perfectly for months suddenly misbehaves on a single weekend in spring or autumn — reports off by an hour, scheduled jobs fir…

by Cassian Vale