pickuma.
Dev Knowledge

Floating Point: Why 0.1 + 0.2 Is Not 0.3

Type 0.1 + 0.2 into almost any language and you get 0.30000000000000004. Here is why IEEE 754 binary floating point does that — and how to handle it correctly.

5 min read

Open a Python REPL, a Node console, or a Ruby prompt and type 0.1 + 0.2. You will not get 0.3. You will get 0.30000000000000004. This is not a bug in any one language — it is how nearly all hardware represents fractional numbers, and understanding it will save you from a class of subtle errors.

Numbers Are Stored in Binary, and Binary Has Limits

Most languages represent decimals using IEEE 754, the standard for binary floating-point arithmetic. A typical double (64-bit float) packs a number into three parts: a sign bit, an exponent, and a mantissa (also called the significand). Think of it as scientific notation in base 2: the value is roughly sign × mantissa × 2^exponent. With 64 bits, the mantissa gets 52 bits, giving you about 15 to 17 significant decimal digits of precision.

The catch is the base 2 part. Just as you cannot write 1/3 exactly in decimal — it is 0.3333… forever — you cannot write certain decimal fractions exactly in binary. A fraction has a finite binary representation only if its denominator is a power of two. So 0.5 (1/2) and 0.25 (1/4) are exact. But 0.1 is 1/10, and 10 is not a power of two, so in binary 0.1 becomes a repeating fraction:

0.1 (decimal) = 0.0001100110011001100... (binary, repeating forever)

Since the mantissa is finite, the machine stores the nearest representable value to 0.1, not 0.1 itself. The same happens to 0.2. Neither is the number you typed — each is off by a tiny amount.

Where the Stray Digits Come From

When you compute 0.1 + 0.2, you are not adding the true values. You are adding the two rounded approximations, then rounding the result again to fit back into a double. Those small errors happen to push the sum just above the stored value of 0.3.

>>> 0.1 + 0.2
0.30000000000000004
>>> (0.1 + 0.2) == 0.3
False
>>> 0.1 + 0.2 - 0.3
5.551115123125783e-17

The leftover 5.5e-17 is the accumulated rounding error. With a single operation it is invisibly small, but errors can accumulate: a loop that adds 0.1 ten thousand times will drift measurably away from 1000. The more operations you chain, the more rounding compounds.

When Floats Are the Wrong Tool

Floating point is the right choice for measurements, physics, graphics, and machine learning — anywhere small relative error is acceptable and speed matters. It is the wrong choice when exactness is required, and money is the classic example. Charging a customer $0.30000000000000004 or watching a running total drift by a penny is unacceptable.

You have two solid alternatives:

  • Integers in the smallest unit. Store money as a whole number of cents (or satoshis, or tenths of a cent) and only format to a decimal point for display. 30 cents is exact; 0.30 dollars is not.
  • A decimal or fixed-point type. Many languages provide arbitrary-precision decimal types — Python’s decimal.Decimal, Java’s BigDecimal, C#‘s decimal, SQL’s NUMERIC/DECIMAL. These store numbers in base 10, so 0.1 + 0.2 is exactly 0.3, at the cost of speed.

The rule of thumb: if a human will count the result and care about the last digit, do not use a raw float.

FAQ

Is this a Python bug? It does not happen in my calculator app.+
It is not a Python bug — it is IEEE 754 behavior shared by C, Java, JavaScript, Go, Rust, and most hardware. Calculator apps hide it by rounding the display to a few digits or by using decimal arithmetic internally, but the same approximation is happening underneath.
Does using float instead of double fix it?+
No. A 32-bit float has even less precision than a 64-bit double, so the error is larger, not smaller. More bits push the error further down, but no fixed number of binary digits can represent 0.1 exactly, because its binary expansion never terminates.
Are integers and decimal types slower?+
Decimal types are noticeably slower than hardware floats because they are usually implemented in software rather than on the CPU's floating-point unit. Integer math is fast, which is why storing money in cents is the common high-performance choice. For most business apps the difference is irrelevant next to correctness.

Related reading

See all Dev Knowledge articles →

Get the best tools, weekly

One email every Friday. No spam, unsubscribe anytime.