> Note that in python there is a math.fsum function which return a perfectly rounded summation of floats.
Quirks of the underlying data can yield surprising results.
I was playing around with the "well-known" floating point error result of 0.3 - 0.2 - 0.1 = some small number (instead of 0), and found:
>>> sum((0.3, -0.2, -0.1) * 1_000_000) / 3e6
-2.775557561562891e-23
>>> math.fsum((0.3, -0.2, -0.1) * 1_000_000) / 3e6
-9.25185853854297e-18
>>> stable_mean((0.3, -0.2, -0.1) * 1_000_000)
-1.387894586067203e-17
Namely, the "naive" mean yielded the smallest error (due to cancellation lining up just right such that it's capped after two rounds), fsum yielded a nominally larger one, and stable_mean yielded the biggest error.
Of course, if you sort the values (such that we're accumulating -0.2 + ... -0.2 + -0.1 + ... + -0.1 + 0.3 + ... + 0.3, then sum performs much worse, stable_mean is a little worse, and fsum performs exactly the same.
>>> sum(sorted((0.3, -0.2, -0.1) * 1_000_000)) / 3e6
-1.042215244884126e-12
>>> math.fsum(sorted((0.3, -0.2, -0.1) * 1_000_000)) / 3e6
-9.25185853854297e-18
>>> stable_mean(sorted((0.3, -0.2, -0.1) * 1_000_000))
-3.0046468865706775e-16
edit: Naturally, if you want accurate decimal calculations, you should consider using decimal.Decimal or fractions.Fraction (albeit at the cost of significant performance). Using numpy.float128 will help, but it's still subject to rounding errors due to imprecise representation.