这是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) - y
和t - sum - y
之间是否有任何区别?括号不是多余的,因为-
是左关联的吗?
答案 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
相比,sum
和y
通常相对较大。因此,如果您没有按照正确的顺序执行操作,那么您经常会遇到上述示例中的情况,如果您没有按照正确的顺序执行操作,则会得到不太准确的结果。