使用 hypot() 是否有任何意义1+ _C2-----√1+c2,实数0≤c≤1 _ _ _ _0≤c≤1

计算科学 数值分析
2021-12-04 18:35:03

形式的表达式时应该使用传统智慧std::hypotr=x2+y2

在我的示例中,我的表达式是,其中我的第一直觉是去实现——我对双精度和浮点变量都感兴趣。在我的问题中,对于大多数情况r=1+c20c1,chypot()c1

但是,快速阅读Wikipedia表明我可能在浪费我的(CPU)时间。由于的建议实现是:x>y

r=x2+y2=x2(1+(y/x)2)=|x|1+(y/x)2

然而,在我的例子中因此它在代数上与天真的实现相同。x=1r=1+y2

在这个问题中不使用会有什么影响,hypot()还有其他数字陷阱需要寻找吗?

1个回答

摘要:如果您有 FMA,则使用它最便宜最准确,否则。但是,在我的测试中,差异非常小:在 1065353216 个 32 位浮点数中,第一个公式更好 532509 倍 (0.05%),更差 382159 倍 (0.035%),并且没有一个公式的错误比 1 ulp 差,所以显而易见就足够了。sqrt(fma(c, c, 1))sqrt(1+c*c)0c1sqrt(1+c*c)

这是一个很好的观点,维基百科有时可能有点不可靠。解决这些类型问题的一种好方法是使用已经实现hypot的成熟库,例如openlibm(https://github.com/JuliaLang/openlibm)。

引用解释它的源代码注释(https://github.com/JuliaLang/openlibm/blob/master/src/e_hypot.c):

/* __ieee754_hypot(x,y)
 *
 * Method :                  
 *  If (assume round-to-nearest) z=x*x+y*y 
 *  has error less than sqrt(2)/2 ulp, than 
 *  sqrt(z) has error less than 1 ulp (exercise).
 *
 *  So, compute sqrt(x*x+y*y) with some care as 
 *  follows to get the error below 1 ulp:
 *
 *  Assume x>y>0;
 *  (if possible, set rounding to round-to-nearest)
 *  1. if x > 2y  use
 *      x1*x1+(y*y+(x2*(x+x1))) for x*x+y*y
 *  where x1 = x with lower 32 bits cleared, x2 = x-x1; else
 *  2. if x <= 2y use
 *      t1*y1+((x-y)*(x-y)+(t1*y2+t2*y))
 *  where t1 = 2x with lower 32 bits cleared, t2 = 2x-t1, 
 *  y1= y with lower 32 bits chopped, y2 = y-y1.
 *      
 *  NOTE: scaling may be necessary if some argument is too 
 *        large or too tiny
 *
 * Special cases:
 *  hypot(x,y) is INF if x or y is +INF or -INF; else
 *  hypot(x,y) is NAN if x or y is NAN.
 *
 * Accuracy:
 *  hypot(x,y) returns sqrt(x^2+y^2) with error less 
 *  than 1 ulps (units in the last place) 
 */

因此,如果您可以足够准确地,您将不会出现上溢/下溢),最终结果将是准确的。1+c2|c|1

如果您有一个带有融合乘加 (FMA) 指令的现代 CPU,那么使用fma大多数语言的标准数学库所具有sqrt(fma(c, c, 1))的 .这甚至比hypot的便宜一点。中的错误fma(c, c, 1)最多为12具有四舍五入的 ulp,因此您将获得与 hypot 相同的准确度,但有错误<1ulp,所以这是最好的。

关于hypot实际使用的公式,我真的不明白他们在做什么。它在1+c22c+(c1)2取决于是否c12. 它几乎看起来像是双双算术的一种特殊情况,您可以通过将乘积写成两个数字的和来准确地计算乘积,但我不确定。我想如果他们可以使用 fma,公式会简单得多。在我的测试中,它们最多与平原一样准确1+c2.

如果你尝试会发生什么1+c2直接地?评价的相对误差w^=fl(1+fl(c2))最多是ϵ134ulp,这给出了错误fl(w^)作为1+ϵ11+ϵ278ulp,最多是一个 ulp,所以它也很准确,并且和hypot一样好。