A plain loop (xs.reduce((a, b) => a + b, 0)) rounds to a double after every addition. The error of each step is small, but it compounds, and a large value can erase a small one entirely: 1e20 + 0.1 is 1e20, so [1e20, 0.1, -1e20] sums to 0.
Math.sumPrecise(iterable) fixes this. MDN describes it as summing "as if the floating point numbers are summed up using their precise mathematical values", then converting the result to the nearest 64-bit float. There is one rounding at the end, not one per step. Details from MDN and the proposal:
- It takes an iterable, not variadic arguments:
Math.sumPrecise([0.1, 0.2]). - An empty iterable gives
-0, the floating-point additive identity. - Elements must be Numbers; anything else throws
TypeError(no coercion). - It can't fix input error.
Math.sumPrecise([0.1, 0.2])is still0.30000000000000004, because the literals0.1and0.2are already slightly off and their exact sum rounds to that value.
Availability. It reached Stage 4 at the July 2025 TC39 meeting and is part of ES2026 (TC39's finished-proposals list), and MDN marks it "Baseline 2026", newly available since April 2026. It is not available in Node 24: in Node 24.19 (V8), typeof Math.sumPrecise is 'undefined'. So in portable code, feature-detect it and fall back.
Fallback: compensated summation. Kahan's and Neumaier's algorithms carry the lost low-order bits in a second variable and add them back at the end. Neumaier's variant also handles the case where the next term is larger than the running sum. It is not guaranteed to match the exact rounding that sumPrecise gives in every case, but it is far better than a naive loop.
When you need exact decimal totals (money), scaling to integers or using a decimal library is still the right answer.