考虑以下函数Add12
,取自CRlibm's documentation并修复了几个明显错别字:
让
a
和b
为浮点数,然后以下方法计算两个浮点数s
和r
,以便s
完全+r
=a
+b
,s
是最接近a
+b
的浮点数。
void Add12Cond ( double *s , double *r, double a, double b ) {
double z ;
*s=a+b;
if (ABS(a) > ABS(b)){
z=s−a;
*r=b−z;
} else {
z=s−b;
*r=a−z;
}
}
这看起来与应用于a
和b
的{{3}}非常相似,但有一个明显区别:Kahan的求和算法并不先于确定{{1}中的哪一个而烦恼}或a
拥有最大的b
。它只需要加起来(通常超过两个)。
我认为浮点运算手册邀请读者思考这个差异,但没有给出任何解释。无论如何,我已经考虑了一段时间,我仍然没有任何直觉,为什么Kahan的求和算法可以取消ABS
测试(我现在没有这本书)我最近提到Kahan的求和算法,提醒我这个问题。
答案 0 :(得分:4)
简而言之,Kahan求和的误差范围比Add12
弱。 Kahan求和得到相对于输入绝对值之和的误差。
查看Add12
,它肯定会将s
计算为最接近a+b
的内容。条件是确保z
完全计算(casework!),因此r
是“a+b
的其余部分。特别是,您获得了r + s = a + b
和|r| <= 0.5 ulp(s)
。
如果我们在Add12
中取错了分支,但幅度相差不超过2 epsilon,则z
最多会计算0.5 ulp(z)
*r
},所以1 ulp(z)
最多会计算错误{{1}}。因此,无条件地选择两个分支意味着我们积累的误差与我们假设的东西的ulp成比例。 Kahan求和总是假设新输入较小,因此总误差大致与输入绝对值之和成比例。
许多FORTRAN和。中双精度的便捷可达性 一些ALGOL编译器表明很快就会出现双精度 普遍接受作为解决方案中的独创性的替代品 数值问题。
不幸的是,这篇半页的论文没有给出任何界限或证据。 Kahan求和的误差界限见TAOCP第4.2.2节中的练习19;该练习表明,由khan求和x_1,...,x_n引起的误差受(2 epsilon + O(n epsilon ^ 2))(sum(i = 1..n)| x_i |)的限制。
我打算根据TAOCP中的设置给出一个证明,但是我已经反复和尴尬地屠杀了一段时间了。令人高兴的是,我刚发现David Goldberg did this in the appendix to "What every computer scientist should know about floating-point arithmetic."