我什么时候应该在 sqrtl 上使用 hypot?

l4m*_*4m2 6 c math performance

它已经在这里讨论的是hypot比慢sqrt,因为它处理的情况下,当两个输入是巨大的或微小的,这样sqrt会错误地返回INF或0。

但是,根据一些测试hypot甚至比先转换为更高的精度然后再进行琐碎计算再转换回来还要慢。

那么,在什么情况下我应该使用hypot?只有当没有更大的浮点类型和溢出是一个问题?

编辑:sqrtlhypot在 input 上有所不同a=1,b=1.8e-8,但sqrtl返回更准确的结果:

hypot 1.0
sqrtl 1.000000000000000222044604925031
exact 1.000000000000000161999999999999986878000000000002125764000...
1+eps 1.0000000000000002220446049250313080847263336181640625
Run Code Online (Sandbox Code Playgroud)

确切线,其中的EPS被加入到结果示这里

chq*_*lie 6

该函数计算边长为和double hypot(double x, double y)的直角三角形的斜边长度,或点 ( , ) 距原点的距离。使用这个函数而不是直接公式是明智的,因为误差要小得多。事实上,对于某些参数值,平方可能会导致精度损失(如果值太小,则平方会产生 0),或者值太大会导致无限结果。使用直接公式可能会产生不正确的结果,甚至不在预期范围内:。xyxysqrt(x * x + y * y)max(|x|, |y|) <= hypot(x, y) <= sqrt(2) * max(|x|, |y|)

hypot()使用替代公式来避免这些病态情况,但会付出一定的性能代价,但如果您知道您的参数不会导致精度损失或无限结果,并且您需要以牺牲正确性为代价的额外速度,则可以使用简单的公式sqrt(x * x + y * y)

根据经验,如果xy为零,或者它们的绝对值在 1e-100 和 1e+100 之间,并且1e-4 <= |x|/|y| <= 1e4,sqrt应该没问题。

在您的示例中,b与 相比非常小a,导致精度完全丢失,因为b*b小而a*a无法a*a + b*b与 区分开来a*a。使用 来long double表示中间结果可以获得足够的额外精度,以便a*a + b*b以足够的精度表示来sqrt计算有意义的结果。但由于sqrt(1 + epsilon)大约为1 + epsilon/2,所以结果无论如何都是可用的。


Jea*_*nès 2

这是因为您正在比较不应该的东西...hypot不是转换为更高的精度,计算平方根并转换回更低的精度hypert使用专用算法来确保计算将返回良好的结果,即使对于给定精度来说数字很大或很小。有一个hypotl用于计算长双精度数的长度,您无法使用 来很好地计算sqrtl。并且,long double可能是完全相同的类型double......