Functional Weave
Code in Rust

stats.moving-average@1.0.0

README.md

1,843 bytes · view raw

# stats.moving-average

Smooths a series. Both kinds return one value for every position that has a
full window behind it, so the output has `len(values) - window + 1` entries
and the i-th output lines up with input `i + window - 1`. A series shorter than
the window returns an empty list rather than an error: a chart with too few
points yet should draw nothing, not fail.

- `simple`: the plain mean of the last `window` values.
- `exponential`: alpha = 2 / (window + 1), the usual span convention. It is
  seeded with the simple average of the first window (so its first output
  equals the simple one), then each step is ema + alpha x (value - ema). Seeding
  with the first value instead, as some libraries do, gives different numbers
  for the whole series; the vectors pin this choice down.

**Precision.** Every output is rounded to `decimals` places, half away from
zero, applied to the binary64 value: y = |x| x 10^decimals, r = floor(y), plus
one if y - r >= 0.5, divided back, sign restored, -0 returned as 0. The running
exponential average is carried unrounded; only what is returned is rounded, so
the rounding does not compound. Note that "applied to the binary64 value" is
literal: 1.005 is stored as 1.00499999999999989..., so it rounds to 1.00 at two
places. Callers who need decimal-exact averages of money should average
integer minor units with `stats.weighted-average` instead.

**Why the three languages agree to the bit.** Each window is summed afresh,
left to right (not by a running add-and-subtract, which accumulates error
differently depending on history), and only IEEE-754 +, -, x, / and floor are
used, in the same order in every language. Each of those operations is
correctly rounded by the standard, so TypeScript, Python and Rust hold the
same double before rounding, and so return the same rounded value.