It is known that the naive sqrt(x*x + y*y) approach for computing the hypotenuse suffers from overflow and accuracy issues, see e.g http://www.johndcook.com/blog/2010/06/02/whats-so-hard-about-finding-a-hypotenuse/. This adds hypot support to FFmpeg, a C99 function. On platforms without hypot, this patch does a reaonable workaround, that although not as accurate as GNU libm, is readable and does not suffer from the overflow issue. Improvements can be made separately. Reviewed-by: Michael Niedermayer <michael@niedermayer.cc> Signed-off-by: Ganesh Ajjanagadde <gajjanagadde@gmail.com>tags/n3.0
@@ -1773,6 +1773,7 @@ MATH_FUNCS=" | |||||
exp2 | exp2 | ||||
exp2f | exp2f | ||||
expf | expf | ||||
hypot | |||||
isinf | isinf | ||||
isnan | isnan | ||||
ldexpf | ldexpf | ||||
@@ -5308,6 +5309,7 @@ disabled crystalhd || check_lib libcrystalhd/libcrystalhd_if.h DtsCrystalHDVersi | |||||
atan2f_args=2 | atan2f_args=2 | ||||
copysign_args=2 | copysign_args=2 | ||||
hypot_args=2 | |||||
ldexpf_args=2 | ldexpf_args=2 | ||||
powf_args=2 | powf_args=2 | ||||
@@ -132,6 +132,29 @@ static av_always_inline av_const int avpriv_isnan(double x) | |||||
: avpriv_isnan(x)) | : avpriv_isnan(x)) | ||||
#endif /* HAVE_ISNAN */ | #endif /* HAVE_ISNAN */ | ||||
#if !HAVE_HYPOT | |||||
#undef hypot | |||||
static inline av_const double hypot(double x, double y) | |||||
{ | |||||
double ret, temp; | |||||
x = fabs(x); | |||||
y = fabs(y); | |||||
if (isinf(x) || isinf(y)) | |||||
return av_int2double(0x7ff0000000000000); | |||||
if (x == 0 || y == 0) | |||||
return x + y; | |||||
if (x < y) { | |||||
temp = x; | |||||
x = y; | |||||
y = temp; | |||||
} | |||||
y = y/x; | |||||
return x*sqrt(1 + y*y); | |||||
} | |||||
#endif /* HAVE_HYPOT */ | |||||
#if !HAVE_LDEXPF | #if !HAVE_LDEXPF | ||||
#undef ldexpf | #undef ldexpf | ||||
#define ldexpf(x, exp) ((float)ldexp(x, exp)) | #define ldexpf(x, exp) ((float)ldexp(x, exp)) | ||||