数值稳定 运行 浮点值的平均值

numerically stable running average of floating point values

使用 32 位浮点值,计算平均值的最佳(数值上最准确)方法是什么 - 当开始计算时 - 我还不知道我将拥有多少个值(在下面的示例中我只是遍历一个向量,这样我就知道了,但假设我最后只知道元素数)?

我可以举个例子

float result = 0.f;
for(float num: numbers) {
    result += num;
}
num /= numbers.size();

但随着结果变大,精度也会变大。对于较小的值,在某些时候 result += num; 实际上不会再改变结果。

我可以

float result = numbers[0]
for(int i=1, i<numbers.size(); i++) {
    float frac = (i/float(i+1));
    result = result * frac + numbers[i] * (1.0f-frac);
}

但我似乎会以这种方式对结果应用累积误差。

有没有更好的方法不用去64bit double?

解决此类问题的最著名方法是 Kahan 求和。参见此处:https://en.wikipedia.org/wiki/Kahan_summation_algorithm。假设总和仍然可以表示为单精度浮点数,在最后做一个直线除以找到平均值。

另请参阅此答案以进行一些额外的讨论,要求大致相同: