计算平均值时避免浮点舍入误差

本文关键字:舍入误差 平均值 计算 | 更新日期: 2023-09-27 18:35:11

我正在编写一个简单的扩展,用于计算数组的平均值。除非值非常大,否则它可以正常工作。所以这里有一个例子

const int div = 100;
double num = 0;
for (int i = 0; i < div; i++)
{
    num += double.MaxValue/div;
}
Console.WriteLine(num);
Console.WriteLine(double.MaxValue);

我希望得到double.MaxValue但由于舍入误差而得到Infinity。是否可以更改算法或处理这种情况?我知道有一些技术可以使用浮点数(例如,四舍五入到偶数),但我正在寻找在这种情况下可能会有所帮助的东西。我希望答案不是No, you cannot, just humble yourself, you have no chance when you work with floats

计算平均值时避免浮点舍入误差

一种可能性是不将每个术语除以项目数,而是在之后除以一次总和,以便累积更少的错误......

当然,在这种情况下,MaxValue+MaxValue会溢出。是的,但您的库会通过检测溢出(安排以捕获异常)来巧妙地缓解此问题,并在这种情况下将操作数缩放 1/2。
在除法之后的最后,您将按 2 的适当幂应用反比例。

是的,但是MaxValue,3,-MaxValue的总和可能表现出非常糟糕的准确性(例如回答零而不是1)。

啊,没问题,你可以用这样的代码得到一个完全精确的总和浮点数的精确和,这很容易,模化你必须混合的尺度保护......

一个小的附带效应是,你的平均值不再多一点(n),只是多了一点(哼......哦,运气不好,一些实时应用程序可能会期望 O(n),而且由于您正在编写一个通用库......

因此,为了平衡这两个期望,您可以选择用一种卡汉总和求和,并牺牲一些准确性来换取速度......

哦,但为什么?究竟有什么期望?这是您必须回答的主要问题...您是否更喜欢以速度为代价(想想 crlibm 与 libm)保证最佳准确性的库,以几个极端情况为代价保证最佳速度、无论输入的疾病如何(您的原始问题)或上述混合

不幸的是,你不能把它们放在一起...

正如帕特里夏所说,在任何情况下,都要记录下来。

在循环中,您将它除以零,这就是为什么 num 的值是无限的。