我正在编写一个计算数组平均值的简单扩展。它的工作正常,除非值非常大。所以这是一个例子
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
答案 0 :(得分:1)
一种可能性是不将每个项目除以项目数量,但之后将其除以一次,以便积累更少的错误......
当然,在这种情况下,MaxValue + MaxValue会溢出。是的,但是您的库可以通过检测溢出(安排捕获异常)巧妙地缓解此问题,并在这种情况下将操作数缩放1/2。 在除法结束后,您将通过适当的2的幂来应用反比例。
是的,但是MaxValue,3,-MaxValue的总和可能表现出非常差的准确性(比如回答零而不是1)。
啊,没问题,你可以使用像Precise sum of floating point numbers这样的代码获得一个非常精确的总和,这很简单,模块化你需要混合的规模保护......
一个小的附带影响是你的平均值不再是O(n)更具攻击性(下摆......)。哦,运气不好,一些实时应用程序可能会期望O(n),因为你正在编写一个通用库......
所以,为了平衡两个期望,你可能会选择与Kahan总和相加,并为速度牺牲一些准确性......
哦,但为什么?准确的期望是什么?这是你必须回答的主要问题......你更喜欢一个能够以速度的价格保证最佳准确度的库(想想crlibm vs libm),以一些角落案件的价格提供最佳速度,免除例外无论输入的疾病(你的原始问题),还是上述的混合,都会出现这种情况?
不幸的是,你不能把它们全部放在一起......
在所有情况下,正如帕特里夏所说,记录下来。
答案 1 :(得分:-2)
在循环中,你将它除以零,这就是为什么num的值是无限的。