Kahan 算法中用加法代替减法
这是来自维基百科的 Kahan 求和算法:
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
有什么区别吗?无论如何,括号不是多余的吗?因为 -
是左关联的?
This is the 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
Is there a specific reason why it uses subtraction (as opposed to addition)? If I swap the operands in the computation of c
, can I use addition instead? Somehow, that would make more sense to me:
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
Or is there some weird difference between floating point addition and subtraction I don't know about yet?
Also, is there any difference between (t - sum) - y
and t - sum - y
in the original algorithm? Aren't the parenthesis redundant, since -
is left-associative, anyway?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
据我所知,您的方法与维基百科中的方法完全相同。唯一的区别是 c 的符号(及其含义)颠倒了。在维基百科算法中,
c
是总和的“错误”部分; c=0.0001 意味着总和比应有的要大一些。在您的版本中,c
是对总和的“修正”; c=-0.0001 表示总和应该稍微小一些。我认为括号是为了可读性。它们是为我们服务的,而不是为机器服务的。
As far as I can tell, your method is exactly equivalent to the one from Wikipedia. The only difference is that the sign of
c
-- and therefore its meaning -- is reversed. In the Wikipedia algorithm,c
is the "wrong" part of the sum; c=0.0001 means that the sum is a little bigger than it should be. In your version,c
is the "correction" to the sum; c=-0.0001 means that the sum should be made a little smaller.And I think the parentheses are for readability. They're for us, not the machine.
你的两种算法是等价的。执行期间唯一的区别是 c 的符号。它使用加法的原因是因为在 Kahan 的版本中,
c
代表误差,通常是正确值减去计算值。从括号指定运算顺序的意义上来说,括号是绝对必要的。事实上,正是它们使这个算法发挥作用!
当减法是左关联时(就像在大多数语言中一样),
a - b - c
的计算结果为(a - b) - c
,因此两者是相同的。但 Kahan 算法中的减法是a - (b - c)
,并且不应将其计算为a - b + c
。浮点加法和减法不具有关联性。对于在标准算术中等效的表达式,根据执行运算的顺序,您可能会得到不同的结果。
为了清楚起见,我们使用 3 个小数位的精度。这意味着如果我们得到 4 位数字的结果,我们必须对其进行四舍五入。
现在将
(a - b) - c
与数学上等效的a - (b + c)
进行比较,以获取某些特定值:因此
第二种方法不太准确。
在 Kahan 算法中,
t
和sum
与y
相比通常相对较大。因此,您经常会遇到如上例所示的情况,如果不按正确的顺序执行操作,您将得到不太准确的结果。Your two algorithms are equivalent. The only difference during execution will be the sign of
c
. The reason it uses addition is because in Kahan's version,c
represents the error, which is conventionally the correct minus the computed value.In the sense that parentheses specify the order of operations, the parentheses are absolutely necessary. In fact, they are what makes this algorithm work!
When subtraction is left-associative, as it is in most languages,
a - b - c
evaluates as(a - b) - c
so the two are the same. But the subtraction in the Kahan algorithm isa - (b - c)
, and that should not be evaluated asa - b + c
.Floating-point addition and subtraction are not associative. For expressions that are equivalent in standard arithmetic, you may get different results depending on the order in which you perform the operations.
Let's work with 3 decimal digits of precision, for the sake of clarity. This means that if we get a result with 4 digits, we have to round it.
Now compare
(a - b) - c
with the mathematically equivalenta - (b + c)
for some specific values:with
So the second approach is less accurate.
In the Kahan algorithm,
t
andsum
will usually be relatively large compared toy
. So you often get a situation like in the example above where you would get a less accurate result if you don't do the operations in the correct order.