形式的表达式时应该使用传统智慧std::hypot
在我的示例中,我的表达式是,其中。我的第一直觉是去实现——我对双精度和浮点变量都感兴趣。在我的问题中,对于大多数情况。hypot()
但是,快速阅读Wikipedia表明我可能在浪费我的(CPU)时间。由于的建议实现是:
然而,在我的例子中因此它在代数上与天真的实现相同。
在这个问题中不使用会有什么影响,hypot()
还有其他数字陷阱需要寻找吗?
形式的表达式时应该使用传统智慧std::hypot
在我的示例中,我的表达式是,其中。我的第一直觉是去实现——我对双精度和浮点变量都感兴趣。在我的问题中,对于大多数情况。hypot()
但是,快速阅读Wikipedia表明我可能在浪费我的(CPU)时间。由于的建议实现是:
然而,在我的例子中因此它在代数上与天真的实现相同。
在这个问题中不使用会有什么影响,hypot()
还有其他数字陷阱需要寻找吗?
摘要:如果您有 FMA,则使用它最便宜且最准确,否则。但是,在我的测试中,差异非常小:在 1065353216 个 32 位浮点数中,第一个公式更好 532509 倍 (0.05%),更差 382159 倍 (0.035%),并且没有一个公式的错误比 1 ulp 差,所以显而易见就足够了。sqrt(fma(c, c, 1))
sqrt(1+c*c)
sqrt(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)
*/
因此,如果您可以足够准确地,您将不会出现上溢/下溢),最终结果将是准确的。
如果您有一个带有融合乘加 (FMA) 指令的现代 CPU,那么使用fma
大多数语言的标准数学库所具有sqrt(fma(c, c, 1))
的 .这甚至比hypot的便宜一点。中的错误fma(c, c, 1)
最多为具有四舍五入的 ulp,因此您将获得与 hypot 相同的准确度,但有错误ulp,所以这是最好的。
关于hypot实际使用的公式,我真的不明白他们在做什么。它在和取决于是否. 它几乎看起来像是双双算术的一种特殊情况,您可以通过将乘积写成两个数字的和来准确地计算乘积,但我不确定。我想如果他们可以使用 fma,公式会简单得多。在我的测试中,它们最多与平原一样准确.
如果你尝试会发生什么直接地?评价的相对误差最多是,这给出了错误作为,最多是一个 ulp,所以它也很准确,并且和hypot一样好。