Why Does 0.1 + 0.2 Not Equal 0.3? A Deep Dive into IEEE‑754 Floating‑Point Precision
The article explains why adding 0.1 and 0.2 in JavaScript, Python or C produces 0.30000000000000004 instead of 0.3, by detailing binary floating‑point representation, IEEE‑754 encoding, exponent alignment, rounding rules, and shows C code that reveals the exact stored bits.
Floating‑point rounding error
Adding 0.1 and 0.2 in JavaScript, Python or C does not yield exactly 0.3 because decimal fractions like 0.1 cannot be represented precisely in binary floating‑point format; the result is 0.30000000000000004 (or a longer 57‑digit representation in C).
Binary representation of numbers
Integers are stored as fixed‑size binary values (16‑bit short, 32‑bit int, 64‑bit long). Floating‑point numbers follow the IEEE‑754 standard: a sign bit, an exponent (biased) and a mantissa. Single precision uses 32 bits (1‑8‑23), double precision uses 64 bits (1‑11‑52).
How 0.1 is encoded
In binary, 0.75 = 1.1 × 2⁻¹ can be represented exactly, but 0.1 cannot; it is approximated by the nearest binary fraction, resulting in a mantissa that is slightly larger than the true value. The exponent bias for double precision is 1023, so the stored exponent for 0.1 is 01111111011 (binary 1019), giving an actual exponent of –4.
Demonstrating the stored bits in C
The following C program prints the raw bits of two double variables initialized to 0.1, showing the exact IEEE‑754 pattern.
void printBits(size_t const size, void const * const ptr) {
unsigned char *b = (unsigned char*) ptr;
unsigned char byte;
int i, j;
for (i = size-1; i >= 0; i--) {
for (j = 7; j >= 0; j--) {
byte = (b[i] >> j) & 1;
printf("%u", byte);
}
}
puts("");
}
double a = 0.1;
double b = 0.1;
printBits(sizeof(a), &a);
printBits(sizeof(b), &b);The output confirms the 64‑bit pattern with a sign of 0, exponent 01111111011 and a mantissa beginning with 0x19999….
Why 0.1 + 0.2 still deviates
When adding two floating‑point numbers, the exponents must be aligned. The smaller exponent (0.1) is shifted right, causing loss of low‑order bits. After alignment, the mantissas are added, producing a 53‑bit sum that overflows the 52‑bit mantissa field, so the exponent is incremented and the mantissa is rounded (round‑to‑nearest even). This rounding yields the final binary value that prints as 0.30000000000000004.
Maximum representable values in JavaScript
JavaScript numbers are IEEE‑754 double precision. The largest safe integer is Number.MAX_SAFE_INTEGER (2⁵³‑1 ≈ 9e15). The largest finite value is Number.MAX_VALUE (≈1.79e308). Because integers are stored in the mantissa, JavaScript cannot represent all 64‑bit integer values exactly.
Practical implications
Only about 15 decimal digits of a double are reliable; digits beyond that may be incorrect. When precise decimal arithmetic is required (e.g., financial calculations or astronomical simulations), use rational arithmetic, arbitrary‑precision libraries, or store values as integers representing smallest units.
Comparing floating‑point numbers safely
Instead of direct equality, compare the absolute difference against a tiny epsilon. In ES6, Number.EPSILON provides a suitable default tolerance, e.g., Math.abs((0.1+0.2) - 0.3) < Number.EPSILON.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
ITPUB
Official ITPUB account sharing technical insights, community news, and exciting events.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
