
Why 0.1 + 0.2 Is Not 0.3: IEEE 754 Floating Point, Bit by Bit
Enter 0.1 + 0.2 in a JavaScript console and the result is 0.30000000000000004, not 0.3. Common Python and Java calculations using IEEE 754 binary64 produce the same stored value. This is not a language bug: it follows from converting decimal fractions into finite binary floating-point values and rounding them.
Japanese original published: 2026-05-30
Reproducing the result in binary64 environments
Implementations that round the same inputs to IEEE 754 binary64 and perform the same addition obtain the same stored result. The number of displayed digits can still vary by language and formatting rule.
// JavaScript (Node.js)
> 0.1 + 0.2
0.30000000000000004
> 0.1 + 0.2 === 0.3
false
# Python 3
>>> 0.1 + 0.2
0.30000000000000004
>>> 0.1 + 0.2 == 0.3
False
// Java
System.out.println(0.1 + 0.2);
// 0.30000000000000004
// C, when double is binary64
printf("%.20f", 0.1 + 0.2);
// 0.30000000000000004441
ECMAScript defines Number using IEEE 754-2019 binary64 values. Python documents that float maps to IEEE 754 binary64 on almost all platforms. The C standard does not require every double implementation to be binary64, so its implementation characteristics must be checked.
Why a finite decimal becomes a repeating binary fraction
A fraction can terminate in one base and repeat forever in another. In base 10, 1/3 repeats. In base 2, decimal 0.1 behaves similarly:
0.1 (base 10) = 0.0001100110011001100110011… (base 2)
0.2 (base 10) = 0.0011001100110011001100110…
0.3 (base 10) = 0.0100110011001100110011001…
A reduced fraction has a finite binary expansion if and only if its denominator is a power of two. Thus 1/2, 1/4, and 3/8 terminate in binary, while 1/10 retains a factor of 5 and repeats.
| Decimal | Fraction | Binary form |
|---|---|---|
| 0.5 | 1/2 | 0.1 (finite) |
| 0.25 | 1/4 | 0.01 (finite) |
| 0.375 | 3/8 | 0.011 (finite) |
| 0.1 | 1/10 | 0.000110011… (repeating) |
Inside IEEE 754 binary64: 1 + 11 + 52 bits
A normal binary64 value has one sign bit, an 11-bit exponent field, and a 52-bit stored fraction. The leading 1. of a normal significand is implicit, giving 53 bits of precision.
┌─┬─────────────┬──────────────────────────────────────────────────┐
│S│ exponent 11 │ fraction 52 │
└─┴─────────────┴──────────────────────────────────────────────────┘
normal value = (−1)^S × 1.fraction × 2^(exponent − 1023)
An all-zero exponent field represents signed zero when the fraction is zero and a subnormal number when it is nonzero. An all-one exponent field represents infinity or NaN.
0.1 as binary64
hex: 0x3FB999999999999A
bits: 0 01111111011 1001100110011001100110011001100110011001100110011010
exact stored value:
0.1000000000000000055511151231257827021181583404541015625
The repeating pattern is cut to the available precision and rounded, normally using round-to-nearest, ties-to-even. The independently rounded value of 0.3 is 0x3FD3333333333333, while 0.1 + 0.2 is 0x3FD3333333333334: one binary64 step apart, a difference of about 5.55 × 10−17.
binary16, binary32, binary64, and binary128
| Format | Total bits | Exponent bits | Stored fraction bits | Decimal equivalent of binary precision |
|---|---|---|---|---|
| binary16 | 16 | 5 | 10 | about 3.3 digits |
| binary32 | 32 | 8 | 23 | about 7.2 digits |
| binary64 | 64 | 11 | 52 | about 15.9 digits |
| binary128 | 128 | 15 | 112 | about 34.0 digits |
The decimal figures are p × log10(2), where p includes the implicit leading bit. They are not the same as the number of decimal digits guaranteed to survive every conversion or the digits required for decimal round trips.
0.1 in several formats
binary16: 0x2E66 (error about 2.44e-5)
binary32: 0x3DCCCCCD (error about 1.49e-9)
binary64: 0x3FB999999999999A (error about 5.55e-18)
Where floating-point differences matter
Equality checks
0.1 + 0.2 === 0.3 // false
0.1 + 0.1 + 0.1 === 0.3 // false
0.1 * 10 === 1 // true for this operation sequence
Exact comparison is correct for integers and cases where identical bit patterns are required. Approximate numerical results should instead use absolute and relative tolerances chosen for the scale and purpose of the calculation. One fixed Number.EPSILON test is not suitable for every magnitude.
Money and decimal rules
Store money in an appropriate smallest-unit integer or a decimal type, and define the rounding unit and tie-breaking rule. Decimal.from_float(0.1) shows the exact decimal value of the already-rounded binary64 number; it is not the same as constructing exact decimal Decimal("0.1").
Large integers
JavaScript Number can distinguish every integer only through Number.MAX_SAFE_INTEGER, 253 − 1. The value 253 is representable, but 253 + 1 collides with it. Consider BigInt or strings for IDs and nanosecond Unix timestamps beyond the safe range. A current microsecond Unix timestamp is still below that limit, so evaluate the actual range rather than the unit name alone.
NaN
NaN === NaN // false
Number.isNaN(NaN) // true
Number.isNaN("x") // false
Prefer Number.isNaN() when coercion is not intended. The global isNaN() first converts its argument and can classify non-number inputs unexpectedly.
Practical comparison patterns
// JavaScript: combine absolute and relative tolerance
function nearlyEqual(a, b, relTol = 1e-9, absTol = 0) {
const diff = Math.abs(a - b);
return diff <= Math.max(absTol, relTol * Math.max(Math.abs(a), Math.abs(b)));
}
# Python
math.isclose(a, b, rel_tol=1e-9, abs_tol=0.0)
The tolerances are domain requirements, not universal constants. Values near zero often need a nonzero absolute tolerance; large values usually need a relative tolerance. Accounting, geometry, simulation, and test assertions can require different rules.
Summary
- Decimal 0.1 repeats in binary because its reduced denominator is not a power of two.
- binary64 rounds 0.1 and 0.2 before the addition and rounds the result again.
0.3and0.1 + 0.2are adjacent binary64 values.- Exact equality, approximate comparison, decimal arithmetic, and integer arithmetic solve different problems.
- Use tolerances and numeric types that match the actual domain.
References and sources
- IEEE Std 754-2019 — IEEE Standard for Floating-Point Arithmetic ↗
- Python Tutorial — Floating-Point Arithmetic: Issues and Limitations ↗
- Python Library — decimal.Decimal.from_float ↗
- ECMAScript Language Specification — The Number Type ↗
- ECMAScript Language Specification — Number.MAX_SAFE_INTEGER ↗
- Python Library — math.isclose ↗
- ECMAScript Language Specification — Number.isNaN ↗
- Goldberg (1991) — What Every Computer Scientist Should Know About Floating-Point Arithmetic ↗
Editorial note
This article was prepared with AI assistance and reviewed by an editor before publication. It may still contain factual errors, interpretation mistakes, or outdated information. Check the cited primary sources or official documentation before making an important decision.

