What The Hell Happens When You Add 0.1 Plus 0.2

I spent three years debugging a financial application where transactions were off by fractions of a cent. Turns out it wasn't a logic error. It was floating point arithmetic doing exactly what it was designed to do, just not in the way anyone expects. If you have ever written code that surprised you, this is probably why. Floating point is a way for computers to represent real numbers using binary. Computers only speak in ones and zeros. Real numbers include things like pi, the square root of two, or 0.1. You cannot express every real number exactly in any finite base system, whether that is decimal, binary, or anything else. In decimal, one third is 0.3333 repeating forever. In binary, one tenth is a repeating fraction just like that. So computers store approximations. The standard most people encounter is IEEE 754. It defines how single precision and double precision floats are laid out in memory. A float takes 32 bits. A double takes 64. Those bits are split into a sign bit, an exponent, and a mantissa. The exponent handles the scale. The mantissa handles the significant digits. That is basically it. But the consequences ripple everywhere.

I ran into this head-on when building a scheduling system for hospital MRI machines. The algorithm had to compute time differences down to the millisecond across multiple sessions. Every time I compared two datetime calculations using standard float math, I got results like 0.000999999998 instead of exactly 0.001. The scheduler would reject valid appointments because the comparison returned false. The fix was not to change the algorithm. It was to stop using float for anything that required exact decimal comparison and switch to integer-based timestamp arithmetic. Multiply everything by a thousand, work in milliseconds as whole numbers, and only convert back to floating point for display. That alone eliminated weeks of chasing phantom bugs. Here is something most tutorials do not tell you. The gap between representable float values is not constant. It grows larger as the magnitude increases. Near zero, you have incredible precision. Near one million, the gap between adjacent representable values is about the size of a raindrop compared to an ocean. This is called precision drift and it is why numerical algorithms can become unstable if you are not careful about the order in which you perform operations. Adding small numbers first, then large numbers, usually gives a more accurate result than the reverse. It feels backwards but it is a well known property of how the exponent works. Another thing nobody warns you about until it bites you. Float equality comparisons are almost always wrong. Writing code that checks whether two computed floats are exactly equal will cause failures in production. Even when both values come from the same calculation path, subtle differences in compiler optimization or CPU instruction ordering can produce slightly different bit patterns. The workaround used in production systems is to use an epsilon comparison. You check whether the absolute difference between two values is smaller than a tiny threshold rather than checking for exact equality. Python has math.isclose for this. C has DBL_EPSILON. Java has Double.compare with a tolerance. Use whatever your language gives you and stop writing == checks on floats unless both sides are literals.

The downsides are real. Floating point introduces errors that accumulate. If you run a simulation for millions of iterations, those tiny rounding errors compound. Weather models, physics engines, and financial calculations all deal with this by either using higher precision types, fixed point arithmetic, or specialized libraries. There is no free lunch. You trade simplicity for accuracy and you pick the trade that matches your problem. Single precision float gives you about seven decimal digits of precision. Double precision gives you about fifteen. If you are building a game, single precision is usually fine. If you are building accounting software, neither is fine and you should use a decimal library or work entirely in integer cents. JavaScript only has doubles. That is why 0.1 plus 0.2 does not equal 0.3 in JavaScript. It is not a language bug. It is IEEE 754 doing its thing. If you want to see this for yourself, open any programming language REPL and type 0.1 plus 0.2. You will get 0.30000000000000004. Not a typo. The binary representation of 0.1 and 0.2 cannot combine to produce the exact binary representation of 0.3. That result is the closest representable double to the true mathematical answer. It is correct in the sense that no closer value exists in the format. It is wrong in the sense that your textbook says otherwise.

Get the Full Details

Introduction to floating point Arithmetic | PPTX
Introduction to floating point Arithmetic | PPTX

The practical takeaway is that floating point is a tool with a well defined set of failure modes. Learn those failure modes before they fail you. Know when to switch to integer math, when to use epsilon comparisons, and when to reach for a decimal or rational number type. Most bugs are not caused by misunderstanding the math. They are caused by assuming the math behaves like school math instead of behaving like computer math.