From e0b16cc25c4bae1ac45ec6ce90341f9a7d1ae6b6 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Sat, 19 May 2012 15:35:29 +0000 Subject: Fix ccos, csin, ccosh, csinh overflows (bug 14123). --- math/s_ccosh.c | 43 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 7 deletions(-) (limited to 'math/s_ccosh.c') diff --git a/math/s_ccosh.c b/math/s_ccosh.c index 2c2b71ceab..44c9944466 100644 --- a/math/s_ccosh.c +++ b/math/s_ccosh.c @@ -1,5 +1,5 @@ /* Complex cosine hyperbole function for double. - Copyright (C) 1997, 2011 Free Software Foundation, Inc. + Copyright (C) 1997-2012 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper , 1997. @@ -20,9 +20,8 @@ #include #include #include - #include - +#include __complex__ double __ccosh (__complex__ double x) @@ -37,14 +36,44 @@ __ccosh (__complex__ double x) if (__builtin_expect (icls >= FP_ZERO, 1)) { /* Imaginary part is finite. */ - double sinh_val = __ieee754_sinh (__real__ x); - double cosh_val = __ieee754_cosh (__real__ x); + const int t = (int) ((DBL_MAX_EXP - 1) * M_LN2); double sinix, cosix; __sincos (__imag__ x, &sinix, &cosix); - __real__ retval = cosh_val * cosix; - __imag__ retval = sinh_val * sinix; + if (fabs (__real__ x) > t) + { + double exp_t = __ieee754_exp (t); + double rx = fabs (__real__ x); + if (signbit (__real__ x)) + sinix = -sinix; + rx -= t; + sinix *= exp_t / 2.0; + cosix *= exp_t / 2.0; + if (rx > t) + { + rx -= t; + sinix *= exp_t; + cosix *= exp_t; + } + if (rx > t) + { + /* Overflow (original real part of x > 3t). */ + __real__ retval = DBL_MAX * cosix; + __imag__ retval = DBL_MAX * sinix; + } + else + { + double exp_val = __ieee754_exp (rx); + __real__ retval = exp_val * cosix; + __imag__ retval = exp_val * sinix; + } + } + else + { + __real__ retval = __ieee754_cosh (__real__ x) * cosix; + __imag__ retval = __ieee754_sinh (__real__ x) * sinix; + } } else { -- cgit 1.4.1