# 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.