在Kahan算法中加法而不是减法

时间:2011-12-09 14:22:26

标签: c++ floating-point sum ieee-754 rounding-error

这是Kahan summation algorithm from Wikipedia

function KahanSum(input)
    var sum = 0.0
    var c = 0.0
    for i = 1 to input.length do
        y = input[i] - c    // why subtraction?
        t = sum + y
        c = (t - sum) - y
        sum = t
    return sum

是否有使用减法的具体原因(与添加相反)?如果我在c的计算中交换操作数,我可以使用加法吗?不知怎的,这对我来说更有意义:

function KahanSum(input)
    var sum = 0.0
    var c = 0.0
    for i = 1 to input.length do
        y = input[i] + c    // addition instead of subtraction
        t = sum + y
        c = y - (t - sum)   // swapped operands
        sum = t
    return sum

或者我还不知道浮点加法和减法之间是否存在一些奇怪的区别?

此外,原始算法中(t - sum) - yt - sum - y之间是否有任何区别?括号不是多余的,因为-是左关联的吗?

2 个答案:

答案 0 :(得分:2)

据我所知,你的方法完全等同于维基百科的方法。唯一的区别是c的符号 - 因此它的含义 - 是相反的。在维基百科算法中,c是总和的“错误”部分; c = 0.0001表示总和比它应该大一点。在您的版本中,c是总和的“修正”; c = -0.0001表示总和应该小一些。

我认为括号是为了便于阅读。它们是给我们的,而不是机器。

答案 1 :(得分:2)

你的两个算法是等价的。执行期间唯一的区别是c的标志。它使用加法的原因是因为在Kahan的版本中,c表示错误,通常是正确的减去计算值。

在括号中指定操作顺序的意义上,括号是绝对必要的。事实上,它们是使这种算法有效的原因!

当减法是左关联的时,就像在大多数语言中一样,a - b - c评估为(a - b) - c,因此两者是相同的。但是Kahan算法中的减法为a - (b - c)应该被评估为a - b + c

浮点加法和减法不是关联的。对于在标准算术中等效的表达式,根据执行操作的顺序,可能会得到不同的结果。

为了清楚起见,让我们使用3个十进制数字的精度。这意味着如果我们得到4位数的结果,我们必须对它进行舍入。 现在将(a - b) - c与数学上等效的a - (b + c)进行比较,以获取某些特定值:

(998 - 997) - 5 = 1 - 5 = -4

998 - (997 + 5) = 998 - Round(1002)
                = 998 - 1000 = -2

所以第二种方法不太准确。

在Kahan算法中,与t相比,sumy通常相对较大。因此,如果您没有按照正确的顺序执行操作,那么您经常会遇到上述示例中的情况,如果您没有按照正确的顺序执行操作,则会得到不太准确的结果。