Floating-Point Pitfalls

Floating-point Pitfalls, Math.sumPrecise() and Float16

A double stores a sign bit, an 11-bit exponent (biased by 1023) and a 52-bit fraction, the mantissa. 1/10 repeats forever in binary, as 1/3 does in decimal, so 0.1 is stored as the nearest double. Adding the approximations of 0.1 and 0.2 lands one double above the approximation of 0.3, so 0.1 + 0.2 === 0.3 is false.

0.1 as an IEEE 754 double, and why 0.1 + 0.2 misses 0.3
0.1 as an IEEE 754 double, and why 0.1 + 0.2 misses 0.3

Math.sumPrecise(iterable) (ES2026) adds numbers as if with exact arithmetic and rounds only the final result, so Math.sumPrecise([1e20, 0.1, -1e20]) is 0.1 where a loop gives 0. It is Baseline 2026 (Chrome 147 1 , Firefox 137 555 , Safari 26.2 10 ) but absent from Node.js 25 2,131 , so feature-detect it. It cannot fix 0.1 + 0.2, because the inputs are already approximations. ES2025 added half precision: Float16Array and Math.f16round() (Baseline 2025, Node.js 24+), which store 16-bit floats for GPU and machine-learning buffers (see Float16Array).

Lost precision, a feature-detected sumPrecise() and 16-bit roundingJavaScriptLive
console.log(0.1 + 0.2, [1e20, 0.1, -1e20].reduce((a, b) => a + b));
console.log(Math.sumPrecise?.([1e20, 0.1, -1e20]) ?? "Math.sumPrecise unsupported here");
console.log(Math.f16round(5.05), Math.fround(5.05), new Float16Array([0.1, 65504, 70000]));

Compare floats with a tolerance, round only for display, and compute money in integer cents. The MIT-licensed decimal.js 7,261 (github.com/MikeMcl/decimal.js (https://github.com/MikeMcl/decimal.js 7,261 ), npm 2,036 install decimal.js) stores decimal digits instead of binary fractions: new Decimal(0.3).minus(0.1) is exactly 0.2.