[BUG]: Implement Kahan summation for rolling().mean() to avoid numerical issues
State: closed

- [x] closes #36031
- [x] closes #32761
- [x] closes #10319 
- [x] xref #11645 (fixes the issue expect the 0, will add an additional pr about the doc)
- [x] closes #13254
- [x] tests added / passed
- [x] passes `black pandas`
- [x] passes `git diff upstream/master -u -- "*.py" | flake8 --diff`
- [x] whatsnew entry

I implemented the Kahan summation as suggested by @jreback. I used the variable names from https://en.wikipedia.org/wiki/Kahan_summation_algorithm. If there exists a name convention am not aware of, I am happy to rename the variables.

Labels:
name: Algos
description: Non-arithmetic algos: value_counts, factorize, sorting, isin, clip, shift, diff
name: Window
description: rolling, ewma, expanding

Comments:
Done
I dont think this hits `resample.mean`. I think @jreback might have meant just `rolling.mean`.

Could you do the same for `rolling.sum`? https://github.com/pandas-dev/pandas/issues/13254
@mroeschke 
Yeah you are right. I don't know what I have seen that made me believe ``resample.mean()`` would use the same function. Thanks.

``rolling.sum()`` uses another Cython function. That was not fixed with my implementation. I would be happy to implement Kahan summation there too. Should I open another PR or mix it in here?
> i believe this is shared code with mean; so pls test that as well

sorry I meant rolling.sum

yeah ideally we could share code, though these are simple enough and we don't want to introduce functions that it may be just easier to duplicate what is needed.

ok on this PR or followon to do rolling.sum
@jreback Implemented Kahan summation for ``rolling().sum()``. I also added tests for the issues I've found.

Functions for add_mean, remove_mean, add_sum and remove_sum are quite similar now. We could share this code part for these functions.
Will look into Test failures
Tests should be fixed now. Somehow mixed plus and minus up
@jreback 

I ran asv for rolling. Is the output within the range you expected?

```
      before           after         ratio
     [1b2f1f47]       [c70c91cd]
     <master>         <36031>   
+     1.48±0.02ms       2.64±0.6ms     1.78  rolling.ForwardWindowMethods.time_rolling('Series', 1000, 'int', 'sum')
+     1.77±0.03ms       2.73±0.6ms     1.54  rolling.VariableWindowMethods.time_rolling('Series', '1d', 'float', 'sum')
+        890±10μs      1.28±0.03ms     1.43  rolling.ExpandingMethods.time_expanding('Series', 'float', 'sum')
+     1.69±0.02ms       2.37±0.7ms     1.41  rolling.ForwardWindowMethods.time_rolling('Series', 1000, 'int', 'mean')
+     1.85±0.02ms       2.50±0.2ms     1.35  rolling.ForwardWindowMethods.time_rolling('DataFrame', 1000, 'int', 'sum')
+     1.00±0.03ms      1.32±0.02ms     1.32  rolling.ExpandingMethods.time_expanding('Series', 'float', 'mean')
+     1.26±0.02ms      1.65±0.04ms     1.31  rolling.ExpandingMethods.time_expanding('DataFrame', 'float', 'sum')
+     3.52±0.06ms         4.54±1ms     1.29  rolling.ExpandingMethods.time_expanding('Series', 'float', 'count')
+     1.42±0.03ms       1.81±0.5ms     1.27  rolling.ForwardWindowMethods.time_rolling('Series', 1000, 'float', 'sum')
+     1.35±0.02ms      1.68±0.02ms     1.24  rolling.ExpandingMethods.time_expanding('DataFrame', 'float', 'mean')
+     1.59±0.05ms      1.92±0.06ms     1.21  rolling.Methods.time_rolling('DataFrame', 1000, 'float', 'sum')
+     1.66±0.05ms      1.93±0.05ms     1.16  rolling.Methods.time_rolling('DataFrame', 1000, 'float', 'mean')
+     1.71±0.02ms       1.98±0.2ms     1.16  rolling.VariableWindowMethods.time_rolling('Series', '1h', 'float', 'sum')
+     4.33±0.04ms       4.78±0.3ms     1.10  rolling.Pairwise.time_pairwise(10, 'cov', False)

SOME BENCHMARKS HAVE CHANGED SIGNIFICANTLY.
PERFORMANCE DECREASED.
```

thanks @phofl very nice!

yeah this is a sligth perf hit, but worth the tradeoff