如何避免较大计算中的舍入误差?

计算科学 优化 误差估计
2021-12-07 20:19:55

现在我需要总结超过一千项,然后在我的 Fortran 程序中进行四维积分。我发现有一些数字错误。您能否给我一些建议,如何检查和避免此类一般问题可能出现的舍入错误?

3个回答

以下是一些减少舍入误差影响的技巧。一个简短的方法是增加浮点精度,例如从floatdouble,但很多时候这太昂贵或不可能。

卡汉求和

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,即编译器将所有内容放入一个唯一且直接的命令中,因此不会单独评估前一行。

种类

这是一个非常简单易用的技巧,在对数组进行总和排序并从最小值开始之前。这个想法是小和变得更大,因此减少了舍入误差。

它不能保证有效,但使用它是一个很好的做法。

减法,具有混合符号值的数组

浮点减法不是一个稳定的运算。在数组包含混合有符号值的情况下,需要额外注意避免两个数字的绝对值非常接近。

减少操作

这是一个一般性建议,与一般的值总和没有严格关系。

尝试减少操作以获得结果。一个例子是霍纳方法,其中多项式可以重写为

PN(x)=aN+x(aN1+x(aN2++x(a1+a0x)))

在这种形式下,多项式可以计算为N补充和N乘法,反对N补充和N(N+1)N范式的乘法。(更多细节,维基

您可以尝试从较小的元素开始并添加它们,然后再到更大的值。这减少了舍入误差。

还可以尝试括号的运算符优先级。为了详细说明,假设您要计算

y=ax+bx2+cx3
请注意,您有 10 次算术运算(2 次加法 + 8 次乘法运算),但存在一些舍入误差。在你的实现中,如果你这样写
y=x(a+x(b+cx))
您将进行 7 次操作(2 次加法 + 3 次乘法运算),并且您可能会得到更少的舍入。

舍入误差是由于计算机中实数的有限表示。计算机系统不能使用精确的实数,而只能使用其有理近似值。因此,实际数字不能在计算机中用有限数量的有效数字表示。

在下文中,用 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。就约定形式而言,数字称为小数部分有效数字。