Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When should I use hypot over sqrtl?

It's already discussed here that hypot is slower than sqrt because it handles cases when the two inputs are huge or tiny so that sqrt would wrongly return inf or 0.

However, according to some test, hypot is even slower than first convert to higher precision and then do trivial calculation and convert back.

So, in what case should I use hypot? Only when there's no larger float type and overflow is an issue?

EDIT: sqrtl and hypot differ on input a=1,b=1.8e-8, but sqrtl returns more accurate result:

hypot 1.0
sqrtl 1.000000000000000222044604925031
exact 1.000000000000000161999999999999986878000000000002125764000...
1+eps 1.0000000000000002220446049250313080847263336181640625

Exact lines where an eps is added to result is shown here

like image 726
l4m2 Avatar asked Apr 13 '20 15:04

l4m2


2 Answers

The function double hypot(double x, double y) computes the length of the hypotenuse of a right triangle with sides of x and y, or the distance of the point (x, y) from the origin. Using this function instead of the direct formula sqrt(x * x + y * y) is wise, since the error is much smaller. Indeed for some argument values, squaring can cause either a loss of precision (if the value is too small, squaring it produces 0), or an infinite result of the value is too large. Using the direct formula can produce incorrect results, not even inside the expected range: max(|x|, |y|) <= hypot(x, y) <= sqrt(2) * max(|x|, |y|).

hypot() uses alternative formulae to avoid these pathological cases, at some performance cost, but if you know your arguments are not causing a loss of precision nor an infinite result, and you need extra speed at the expense of correctness, you can use the simple formula sqrt(x * x + y * y).

As a rule of thumb, if x and y are zero or they have an absolute value between 1e-100 and 1e+100 and 1e-4 <= |x|/|y| <= 1e4, sqrt should be fine.

In your example, b is very small compared to a, causing a complete loss of precision because b*b is so much smaller than a*a that a*a + b*b cannot be distinguished from a*a. Using the long double for the intermediary result gains you enough extra precision for a*a + b*b to be represented with enough precision for sqrt to compute a meaningful result. But since sqrt(1 + epsilon) is approximately 1 + epsilon/2, the result is usable anyway.

like image 78
chqrlie Avatar answered Nov 16 '22 17:11

chqrlie


This is because your are comparing things that you should not... hypot is not converting to higher precision, computing the square root and converting back to lower precision. hypot uses a dedicated algorithm to ensure that the computation will return a good result, even if numbers are huge or tiny for a given precision. There is an hypotl to compute the length for long doubles that you cannot compute well using sqrtl. And, long double may be the exact same type than double...

like image 2
Jean-Baptiste Yunès Avatar answered Nov 16 '22 17:11

Jean-Baptiste Yunès