现在我需要总结超过一千项,然后在我的 Fortran 程序中进行四维积分。我发现有一些数字错误。您能否给我一些建议,如何检查和避免此类一般问题可能出现的舍入错误?
如何避免较大计算中的舍入误差?
以下是一些减少舍入误差影响的技巧。一个简短的方法是增加浮点精度,例如从float到double,但很多时候这太昂贵或不可能。
卡汉求和
在Kahan 总结中,想法是弥补上一步中的错误。
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
var y = input[i] - c // So far, so good: c is zero.
var t = sum + y // Alas, sum is big, y small, so low-order digits of y are lost.
c = (t - sum) - y // (t - sum) cancels the high-order part of y; subtracting y recovers negative (low part of y)
sum = t // Algebraically, c should always be zero. Beware overly-aggressive optimizing compilers!
next i // Next time around, the lost low part will be added to y in a fresh attempt.
return sum
变量c是使用新的和元素input[i]逐步使用的校正。c评估时的误差更小,因为游戏中的数字处于同一数量级。重要的一步是这条线
c = (t - sum) - y
是明确评估的。
由于编译器的原因,实现的代码无法生效,请参阅wiki,即编译器将所有内容放入一个唯一且直接的命令中,因此不会单独评估前一行。
种类
这是一个非常简单易用的技巧,在对数组进行总和排序并从最小值开始之前。这个想法是小和变得更大,因此减少了舍入误差。
它不能保证有效,但使用它是一个很好的做法。
减法,具有混合符号值的数组
浮点减法不是一个稳定的运算。在数组包含混合有符号值的情况下,需要额外注意避免两个数字的绝对值非常接近。
减少操作
这是一个一般性建议,与一般的值总和没有严格关系。
尝试减少操作以获得结果。一个例子是霍纳方法,其中多项式可以重写为
在这种形式下,多项式可以计算为补充和乘法,反对补充和范式的乘法。(更多细节,维基)
您可以尝试从较小的元素开始并添加它们,然后再到更大的值。这减少了舍入误差。
还可以尝试括号的运算符优先级。为了详细说明,假设您要计算
舍入误差是由于计算机中实数的有限表示。计算机系统不能使用精确的实数,而只能使用其有理近似值。因此,实际数字不能在计算机中用有限数量的有效数字表示。
在下文中,用 f 小数部分和指数 n 表示以 10 为底的实数是有用的。x = f • 10n。(2.8) 此外,对于 0 以外的任何数,通过方便地选择 n,Fractional 满足 0.1 ≤ | f | <1。例如 3.14 = 0,314 * 10 ^ 1,-0.007856 = • 10 ^ 2 -0.7856。就约定形式而言,数字称为小数部分有效数字。