我有两个代码理论上应该返回完全相同的输出。但是,这不会发生。问题是这两个代码处理非常小的数字(双精度数),大约为 1e-100 左右。我怀疑可能存在一些与此相关的数值问题,并导致两个输出不同,即使它们在理论上应该相同。
处理 1e-100 数量级的数字会导致这样的问题是否真的有意义?如果我可以安全地假设来源是数字问题,我不介意输出的差异。有没有人有一个很好的来源/参考来讨论当他们以这种顺序处理数字时算法的稳定性问题?
谢谢。
我有两个代码理论上应该返回完全相同的输出。但是,这不会发生。问题是这两个代码处理非常小的数字(双精度数),大约为 1e-100 左右。我怀疑可能存在一些与此相关的数值问题,并导致两个输出不同,即使它们在理论上应该相同。
处理 1e-100 数量级的数字会导致这样的问题是否真的有意义?如果我可以安全地假设来源是数字问题,我不介意输出的差异。有没有人有一个很好的来源/参考来讨论当他们以这种顺序处理数字时算法的稳定性问题?
谢谢。
有没有人有一个很好的来源/参考来讨论当他们以这种顺序处理数字时算法的稳定性问题?
想到的第一个参考资料是每个计算机科学家都应该知道的关于浮点运算的知识。它通常涵盖浮点数学。
就数值稳定性而言,最佳参考可能取决于所讨论的数值算法。想到的两个广泛的作品是:
引起问题的不一定是少数人。
您如何检查输出是否“完全相同”?
我会用宽容检查平等。您可以考虑浮点数x
,如果其中一个或成立,y
则相等。fabs(x-y) < 1.0e-6
fabs(x-y) < fabs(x)*1.0e-6
通常,如果存在数值问题,两种算法之间会存在巨大差异。通常,如果算法遇到数值问题,输入的微小变化可能会导致输出的极端变化。
是什么让您认为存在“数字问题”?
如果可能,请更改您的算法以使用 Kahan Summation(又称补偿求和)。来自维基百科:
function KahanSum(input)
var sum = 0.0
var c = 0.0 //A running compensation for lost low-order bits.
for i = 1 to input.length do
y = input[i] - c //So far, so good: c is zero.
t = sum + y //Alas, sum is big, y small, so low-order digits of y are lost.
c = (t - sum) - y //(t - sum) recovers the high-order part of y; subtracting y recovers -(low part of y)
sum = t //Algebraically, c should always be zero. Beware eagerly optimising compilers!
//Next time around, the lost low part will be added to y in a fresh attempt.
return sum
这通过保持累积误差的第二个运行总计来工作,类似于 Bresenham 线绘制算法。最终结果是您获得的精度几乎是数据类型宣传精度的两倍。
我使用的另一种技术是将我的数字从小到大排序(按manitude,忽略符号),然后先加或减小数字,然后是大数字。这样做的好处是,如果您多次添加和减去相同的值,这些数字可能会完全取消并且可以从列表中删除。