npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

exact-sum

v0.1.0

Published

Floating-point summation as an accuracy ladder: naive, pairwise, Neumaier compensated, and correctly rounded exact summation.

Readme

exact-sum

Floating-point summation as a ladder: one contract, four deliberate points on the speed/accuracy curve.

import { exactSum, neumaierSum, pairwiseSum, sum } from 'exact-sum'

sum(xs)          // fastest; error grows with n
pairwiseSum(xs)  // balanced tree; error grows with log n
neumaierSum(xs)  // compensated; error is essentially independent of n
exactSum(xs)     // correctly rounded; the accuracy ceiling

sum([1, 1e100, 1, -1e100]) === 0
neumaierSum([1, 1e100, 1, -1e100]) === 2

Zero runtime dependencies. ESM and TypeScript declarations are included.

Why this exists

JavaScript has good individual summation implementations, but no small package that presents the useful algorithms as a choice and publishes accuracy and speed receipts together.

| incumbent | state of the world | |---|---| | [email protected] | Kahan only; last published in 2014; its dependency tries to compile obsolete jscoverage during install | | math-sum | the ordinary naive loop | | d3-array fsum | excellent correctly rounded summation, but it is one utility inside the larger d3-array package | | @stdlib/blas-ext-base-gsumkbn | a sound compensated implementation inside stdlib's dtype-specific hierarchy | | exact-sum | the whole ladder, zero runtime dependencies, one input contract, oracle-backed receipts |

Measured on Node 24.13.1, Apple Silicon, 2026-07-11. Run npm run bench to reproduce. cyclebench interleaves candidates to reduce machine drift; result agreement is deliberately disabled because the low bits are the subject of the benchmark.

Calls per millisecond (higher is better):

| algorithm | f64×1k | f64×100k | f64×1M | cancellation | |---|---:|---:|---:|---:| | sum | 1,637 | 15.9 | 1.58 | 395 | | pairwiseSum | 755 | 6.18 | 0.705 | 165 | | neumaierSum | 1,009 | 10.8 | 1.03 | 243 | | exactSum | 128 | 0.588 | 0.060 | 49.2 | | d3-array fsum | 120 | 0.634 | 0.064 | 59.8 | | [email protected] | 81.6 | 0.836 | 0.084 | 19.6 |

Maximum measured ULP error (lower is better):

| algorithm | f64×1k | f64×100k | f64×1M | cancellation | |---|---:|---:|---:|---:| | sum | 4 | 206 | 233 | 6.00e15 | | pairwiseSum | 1 | 8 | 0 | 6.01e15 | | neumaierSum | 0 | 0 | 0 | 0 | | exactSum | 0 | 0 | 0 | 0 | | d3-array fsum | 0 | 0 | 0 | 0 | | [email protected] | 0 | 5 | 0 | 6.00e15 |

The speed curve is honest: naive is fastest; pairwise runs at roughly 40–50% of its rate; Neumaier is the strongest constant-memory option; exact summation is about 8–27× slower than naive here. d3 wins narrowly on the large exact workloads and cancellation, while this package's exactSum wins narrowly at 1k. Those are measurements, not promises. The zero-error cells for Neumaier are properties of these inputs, not a guarantee; only the exact algorithms guarantee them.

Choosing a rung

| use case | choose | why | |---|---|---| | UI totals, telemetry, rough statistics | sum | smallest constant and maximum throughput | | probability mass, reductions over large arrays | pairwiseSum | much slower error growth for about one extra unit of control overhead | | accounting aggregates, simulation, scientific data | neumaierSum | strong compensation in constant memory, including the classic Kahan miss | | computational geometry, reproducible reductions, reference results | exactSum | permutation-invariant, correctly rounded answer |

API

Every array-taking function accepts readonly number[] | Float64Array and does not mutate it.

sum(xs): number
pairwiseSum(xs): number
neumaierSum(xs): number
exactSum(xs): number

cumulativeSum(xs): number[]
// compensated running prefix sums

twoSum(a, b): [sum: number, residual: number]
// error-free transform for finite inputs when a + b does not overflow

fast2Sum(a, b): [sum: number, residual: number]
// three-operation transform; precondition: |a| >= |b|

NaN propagates. A single sign of infinity produces that infinity; mixing +Infinity and -Infinity produces NaN. Empty sums are +0. As with IEEE addition, cancellation normally produces +0; exactSum([-0]) preserves the single input's -0, while callers should not use a zero result's sign as numerical information.

exactSum uses a Shewchuk nonoverlapping expansion on the ordinary path. If a finite intermediate expansion component overflows, it falls back to exact binary-rational BigInt accumulation so that cases such as [1e308, 1e308, -1e308, -1e308] still return 0 rather than throwing or silently returning NaN.

Verification

The tests decode every binary64 input as an exact integer times a power of two, accumulate those values over BigInt, and round once using IEEE 754 round-to-nearest, ties-to-even. That independent oracle checks every rung on adversarial cancellation vectors and seeded mixed-sign, mixed-magnitude arrays at every power-of-two size from 2 through 2²⁰.

exactSum must equal the oracle bit-for-bit and under permutations. The other rungs are measured in ULPs and checked against their forward-error bounds. twoSum and fast2Sum are checked as exact real identities with the same oracle. Empty input, signed zero, infinities, NaN, overflow, and denormals have dedicated tests. The derivation and invariants are in DESIGN.md.

To work on the benchmark locally, use npm install --ignore-scripts: the required historical kahan dev dependency has a broken legacy install script; its summation function itself remains runnable.

License

MIT © Xyra Sinclair