数值稳定 运行 浮点值的平均值
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。假设总和仍然可以表示为单精度浮点数,在最后做一个直线除以找到平均值。
另请参阅此答案以进行一些额外的讨论,要求大致相同:
使用 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。假设总和仍然可以表示为单精度浮点数,在最后做一个直线除以找到平均值。
另请参阅此答案以进行一些额外的讨论,要求大致相同: