From 638a572eb0d9af9588bf79e14badc1efefe59d99 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Mon, 9 Jul 2012 11:06:34 +0000 Subject: Fix clog, clog10 spurious underflow exceptions (bug 14337). --- math/libm-test.inc | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ math/s_clog.c | 23 ++++++++------ math/s_clog10.c | 23 ++++++++------ math/s_clog10f.c | 23 ++++++++------ math/s_clog10l.c | 23 ++++++++------ math/s_clogf.c | 23 ++++++++------ math/s_clogl.c | 23 ++++++++------ 7 files changed, 174 insertions(+), 54 deletions(-) (limited to 'math') diff --git a/math/libm-test.inc b/math/libm-test.inc index 27c53a1..a9cc2bd 100644 --- a/math/libm-test.inc +++ b/math/libm-test.inc @@ -2419,6 +2419,51 @@ clog_test (void) TEST_c_c (clog, 0x1p-16440L, 0x1p-16441L, -11395.22807662984378194141292922726786191L, 0.4636476090008061162142562314612144020285L); #endif + TEST_c_c (clog, 0x1p-149L, 0x1.fp+127L, 88.69109041335841930424871526389807508374L, M_PI_2l); + TEST_c_c (clog, -0x1p-149L, 0x1.fp+127L, 88.69109041335841930424871526389807508374L, M_PI_2l); + TEST_c_c (clog, 0x1p-149L, -0x1.fp+127L, 88.69109041335841930424871526389807508374L, -M_PI_2l); + TEST_c_c (clog, -0x1p-149L, -0x1.fp+127L, 88.69109041335841930424871526389807508374L, -M_PI_2l); + TEST_c_c (clog, -0x1.fp+127L, 0x1p-149L, 88.69109041335841930424871526389807508374L, M_PIl); + TEST_c_c (clog, -0x1.fp+127L, -0x1p-149L, 88.69109041335841930424871526389807508374L, -M_PIl); +#ifdef TEST_FLOAT + TEST_c_c (clog, 0x1.fp+127L, 0x1p-149L, 88.69109041335841930424871526389807508374L, plus_zero, UNDERFLOW_EXCEPTION); + TEST_c_c (clog, 0x1.fp+127L, -0x1p-149L, 88.69109041335841930424871526389807508374L, minus_zero, UNDERFLOW_EXCEPTION); +#endif + +#ifndef TEST_FLOAT + TEST_c_c (clog, 0x1p-1074L, 0x1.fp+1023L, 709.7509641950694165420886960904242800794L, M_PI_2l); + TEST_c_c (clog, -0x1p-1074L, 0x1.fp+1023L, 709.7509641950694165420886960904242800794L, M_PI_2l); + TEST_c_c (clog, 0x1p-1074L, -0x1.fp+1023L, 709.7509641950694165420886960904242800794L, -M_PI_2l); + TEST_c_c (clog, -0x1p-1074L, -0x1.fp+1023L, 709.7509641950694165420886960904242800794L, -M_PI_2l); + TEST_c_c (clog, -0x1.fp+1023L, 0x1p-1074L, 709.7509641950694165420886960904242800794L, M_PIl); + TEST_c_c (clog, -0x1.fp+1023L, -0x1p-1074L, 709.7509641950694165420886960904242800794L, -M_PIl); +#endif +#if defined TEST_DOUBLE || (defined TEST_LDOUBLE && LDBL_MAX_EXP == 1024) + TEST_c_c (clog, 0x1.fp+1023L, 0x1p-1074L, 709.7509641950694165420886960904242800794L, plus_zero, UNDERFLOW_EXCEPTION); + TEST_c_c (clog, 0x1.fp+1023L, -0x1p-1074L, 709.7509641950694165420886960904242800794L, minus_zero, UNDERFLOW_EXCEPTION); +#endif + +#if defined TEST_LDOUBLE && LDBL_MAX_EXP >= 16384 + TEST_c_c (clog, 0x1p-16445L, 0x1.fp+16383L, 11356.49165759582936919077408168801636572L, M_PI_2l); + TEST_c_c (clog, -0x1p-16445L, 0x1.fp+16383L, 11356.49165759582936919077408168801636572L, M_PI_2l); + TEST_c_c (clog, 0x1p-16445L, -0x1.fp+16383L, 11356.49165759582936919077408168801636572L, -M_PI_2l); + TEST_c_c (clog, -0x1p-16445L, -0x1.fp+16383L, 11356.49165759582936919077408168801636572L, -M_PI_2l); + TEST_c_c (clog, -0x1.fp+16383L, 0x1p-16445L, 11356.49165759582936919077408168801636572L, M_PIl); + TEST_c_c (clog, -0x1.fp+16383L, -0x1p-16445L, 11356.49165759582936919077408168801636572L, -M_PIl); + TEST_c_c (clog, 0x1.fp+16383L, 0x1p-16445L, 11356.49165759582936919077408168801636572L, plus_zero, UNDERFLOW_EXCEPTION); + TEST_c_c (clog, 0x1.fp+16383L, -0x1p-16445L, 11356.49165759582936919077408168801636572L, minus_zero, UNDERFLOW_EXCEPTION); +# if LDBL_MANT_DIG >= 113 + TEST_c_c (clog, 0x1p-16494L, 0x1.fp+16383L, 11356.49165759582936919077408168801636572L, M_PI_2l); + TEST_c_c (clog, -0x1p-16494L, 0x1.fp+16383L, 11356.49165759582936919077408168801636572L, M_PI_2l); + TEST_c_c (clog, 0x1p-16494L, -0x1.fp+16383L, 11356.49165759582936919077408168801636572L, -M_PI_2l); + TEST_c_c (clog, -0x1p-16494L, -0x1.fp+16383L, 11356.49165759582936919077408168801636572L, -M_PI_2l); + TEST_c_c (clog, -0x1.fp+16383L, 0x1p-16494L, 11356.49165759582936919077408168801636572L, M_PIl); + TEST_c_c (clog, -0x1.fp+16383L, -0x1p-16494L, 11356.49165759582936919077408168801636572L, -M_PIl); + TEST_c_c (clog, 0x1.fp+16383L, 0x1p-16494L, 11356.49165759582936919077408168801636572L, plus_zero, UNDERFLOW_EXCEPTION); + TEST_c_c (clog, 0x1.fp+16383L, -0x1p-16494L, 11356.49165759582936919077408168801636572L, minus_zero, UNDERFLOW_EXCEPTION); +# endif +#endif + END (clog, complex); } @@ -2503,6 +2548,51 @@ clog10_test (void) TEST_c_c (clog10, 0x1p-16440L, 0x1p-16441L, -4948.884673709346821106688037612752099609L, 0.2013595981366865710389502301937289472543L); #endif + TEST_c_c (clog10, 0x1p-149L, 0x1.fp+127L, 38.51805116050395969095658815123105801479L, 0.6821881769209206737428918127156778851051L); + TEST_c_c (clog10, -0x1p-149L, 0x1.fp+127L, 38.51805116050395969095658815123105801479L, 0.6821881769209206737428918127156778851051L); + TEST_c_c (clog10, 0x1p-149L, -0x1.fp+127L, 38.51805116050395969095658815123105801479L, -0.6821881769209206737428918127156778851051L); + TEST_c_c (clog10, -0x1p-149L, -0x1.fp+127L, 38.51805116050395969095658815123105801479L, -0.6821881769209206737428918127156778851051L); + TEST_c_c (clog10, -0x1.fp+127L, 0x1p-149L, 38.51805116050395969095658815123105801479L, 1.364376353841841347485783625431355770210L); + TEST_c_c (clog10, -0x1.fp+127L, -0x1p-149L, 38.51805116050395969095658815123105801479L, -1.364376353841841347485783625431355770210L); +#ifdef TEST_FLOAT + TEST_c_c (clog10, 0x1.fp+127L, 0x1p-149L, 38.51805116050395969095658815123105801479L, plus_zero, UNDERFLOW_EXCEPTION); + TEST_c_c (clog10, 0x1.fp+127L, -0x1p-149L, 38.51805116050395969095658815123105801479L, minus_zero, UNDERFLOW_EXCEPTION); +#endif + +#ifndef TEST_FLOAT + TEST_c_c (clog10, 0x1p-1074L, 0x1.fp+1023L, 308.2409272754311106024666378243768099991L, 0.6821881769209206737428918127156778851051L); + TEST_c_c (clog10, -0x1p-1074L, 0x1.fp+1023L, 308.2409272754311106024666378243768099991L, 0.6821881769209206737428918127156778851051L); + TEST_c_c (clog10, 0x1p-1074L, -0x1.fp+1023L, 308.2409272754311106024666378243768099991L, -0.6821881769209206737428918127156778851051L); + TEST_c_c (clog10, -0x1p-1074L, -0x1.fp+1023L, 308.2409272754311106024666378243768099991L, -0.6821881769209206737428918127156778851051L); + TEST_c_c (clog10, -0x1.fp+1023L, 0x1p-1074L, 308.2409272754311106024666378243768099991L, 1.364376353841841347485783625431355770210L); + TEST_c_c (clog10, -0x1.fp+1023L, -0x1p-1074L, 308.2409272754311106024666378243768099991L, -1.364376353841841347485783625431355770210L); +#endif +#if defined TEST_DOUBLE || (defined TEST_LDOUBLE && LDBL_MAX_EXP == 1024) + TEST_c_c (clog10, 0x1.fp+1023L, 0x1p-1074L, 308.2409272754311106024666378243768099991L, plus_zero, UNDERFLOW_EXCEPTION); + TEST_c_c (clog10, 0x1.fp+1023L, -0x1p-1074L, 308.2409272754311106024666378243768099991L, minus_zero, UNDERFLOW_EXCEPTION); +#endif + +#if defined TEST_LDOUBLE && LDBL_MAX_EXP >= 16384 + TEST_c_c (clog10, 0x1p-16445L, 0x1.fp+16383L, 4932.061660674182269085496060792589701158L, 0.6821881769209206737428918127156778851051L); + TEST_c_c (clog10, -0x1p-16445L, 0x1.fp+16383L, 4932.061660674182269085496060792589701158L, 0.6821881769209206737428918127156778851051L); + TEST_c_c (clog10, 0x1p-16445L, -0x1.fp+16383L, 4932.061660674182269085496060792589701158L, -0.6821881769209206737428918127156778851051L); + TEST_c_c (clog10, -0x1p-16445L, -0x1.fp+16383L, 4932.061660674182269085496060792589701158L, -0.6821881769209206737428918127156778851051L); + TEST_c_c (clog10, -0x1.fp+16383L, 0x1p-16445L, 4932.061660674182269085496060792589701158L, 1.364376353841841347485783625431355770210L); + TEST_c_c (clog10, -0x1.fp+16383L, -0x1p-16445L, 4932.061660674182269085496060792589701158L, -1.364376353841841347485783625431355770210L); + TEST_c_c (clog10, 0x1.fp+16383L, 0x1p-16445L, 4932.061660674182269085496060792589701158L, plus_zero, UNDERFLOW_EXCEPTION); + TEST_c_c (clog10, 0x1.fp+16383L, -0x1p-16445L, 4932.061660674182269085496060792589701158L, minus_zero, UNDERFLOW_EXCEPTION); +# if LDBL_MANT_DIG >= 113 + TEST_c_c (clog10, 0x1p-16494L, 0x1.fp+16383L, 4932.061660674182269085496060792589701158L, 0.6821881769209206737428918127156778851051L); + TEST_c_c (clog10, -0x1p-16494L, 0x1.fp+16383L, 4932.061660674182269085496060792589701158L, 0.6821881769209206737428918127156778851051L); + TEST_c_c (clog10, 0x1p-16494L, -0x1.fp+16383L, 4932.061660674182269085496060792589701158L, -0.6821881769209206737428918127156778851051L); + TEST_c_c (clog10, -0x1p-16494L, -0x1.fp+16383L, 4932.061660674182269085496060792589701158L, -0.6821881769209206737428918127156778851051L); + TEST_c_c (clog10, -0x1.fp+16383L, 0x1p-16494L, 4932.061660674182269085496060792589701158L, 1.364376353841841347485783625431355770210L); + TEST_c_c (clog10, -0x1.fp+16383L, -0x1p-16494L, 4932.061660674182269085496060792589701158L, -1.364376353841841347485783625431355770210L); + TEST_c_c (clog10, 0x1.fp+16383L, 0x1p-16494L, 4932.061660674182269085496060792589701158L, plus_zero, UNDERFLOW_EXCEPTION); + TEST_c_c (clog10, 0x1.fp+16383L, -0x1p-16494L, 4932.061660674182269085496060792589701158L, minus_zero, UNDERFLOW_EXCEPTION); +# endif +#endif + END (clog10, complex); } diff --git a/math/s_clog.c b/math/s_clog.c index 15e5e9c..2249e86 100644 --- a/math/s_clog.c +++ b/math/s_clog.c @@ -40,25 +40,30 @@ __clog (__complex__ double x) else if (__builtin_expect (rcls != FP_NAN && icls != FP_NAN, 1)) { /* Neither real nor imaginary part is NaN. */ + double absx = fabs (__real__ x), absy = fabs (__imag__ x); double d; int scale = 0; - if (fabs (__real__ x) > DBL_MAX / 2.0 - || fabs (__imag__ x) > DBL_MAX / 2.0) + if (absx > DBL_MAX / 2.0) { scale = -1; - __real__ x = __scalbn (__real__ x, scale); - __imag__ x = __scalbn (__imag__ x, scale); + absx = __scalbn (absx, scale); + absy = (absy >= DBL_MIN * 2.0 ? __scalbn (absy, scale) : 0.0); } - else if (fabs (__real__ x) < DBL_MIN - && fabs (__imag__ x) < DBL_MIN) + else if (absy > DBL_MAX / 2.0) + { + scale = -1; + absx = (absx >= DBL_MIN * 2.0 ? __scalbn (absx, scale) : 0.0); + absy = __scalbn (absy, scale); + } + else if (absx < DBL_MIN && absy < DBL_MIN) { scale = DBL_MANT_DIG; - __real__ x = __scalbn (__real__ x, scale); - __imag__ x = __scalbn (__imag__ x, scale); + absx = __scalbn (absx, scale); + absy = __scalbn (absy, scale); } - d = __ieee754_hypot (__real__ x, __imag__ x); + d = __ieee754_hypot (absx, absy); __real__ result = __ieee754_log (d) - scale * M_LN2; __imag__ result = __ieee754_atan2 (__imag__ x, __real__ x); diff --git a/math/s_clog10.c b/math/s_clog10.c index 9d366d6..cf5fb8a 100644 --- a/math/s_clog10.c +++ b/math/s_clog10.c @@ -43,25 +43,30 @@ __clog10 (__complex__ double x) else if (__builtin_expect (rcls != FP_NAN && icls != FP_NAN, 1)) { /* Neither real nor imaginary part is NaN. */ + double absx = fabs (__real__ x), absy = fabs (__imag__ x); double d; int scale = 0; - if (fabs (__real__ x) > DBL_MAX / 2.0 - || fabs (__imag__ x) > DBL_MAX / 2.0) + if (absx > DBL_MAX / 2.0) { scale = -1; - __real__ x = __scalbn (__real__ x, scale); - __imag__ x = __scalbn (__imag__ x, scale); + absx = __scalbn (absx, scale); + absy = (absy >= DBL_MIN * 2.0 ? __scalbn (absy, scale) : 0.0); } - else if (fabs (__real__ x) < DBL_MIN - && fabs (__imag__ x) < DBL_MIN) + else if (absy > DBL_MAX / 2.0) + { + scale = -1; + absx = (absx >= DBL_MIN * 2.0 ? __scalbn (absx, scale) : 0.0); + absy = __scalbn (absy, scale); + } + else if (absx < DBL_MIN && absy < DBL_MIN) { scale = DBL_MANT_DIG; - __real__ x = __scalbn (__real__ x, scale); - __imag__ x = __scalbn (__imag__ x, scale); + absx = __scalbn (absx, scale); + absy = __scalbn (absy, scale); } - d = __ieee754_hypot (__real__ x, __imag__ x); + d = __ieee754_hypot (absx, absy); __real__ result = __ieee754_log10 (d) - scale * M_LOG10_2; __imag__ result = M_LOG10E * __ieee754_atan2 (__imag__ x, __real__ x); diff --git a/math/s_clog10f.c b/math/s_clog10f.c index 11bb0bb..5a0c370d 100644 --- a/math/s_clog10f.c +++ b/math/s_clog10f.c @@ -43,25 +43,30 @@ __clog10f (__complex__ float x) else if (__builtin_expect (rcls != FP_NAN && icls != FP_NAN, 1)) { /* Neither real nor imaginary part is NaN. */ + float absx = fabsf (__real__ x), absy = fabsf (__imag__ x); float d; int scale = 0; - if (fabsf (__real__ x) > FLT_MAX / 2.0f - || fabsf (__imag__ x) > FLT_MAX / 2.0f) + if (absx > FLT_MAX / 2.0f) { scale = -1; - __real__ x = __scalbnf (__real__ x, scale); - __imag__ x = __scalbnf (__imag__ x, scale); + absx = __scalbnf (absx, scale); + absy = (absy >= FLT_MIN * 2.0f ? __scalbnf (absy, scale) : 0.0f); } - else if (fabsf (__real__ x) < FLT_MIN - && fabsf (__imag__ x) < FLT_MIN) + else if (absy > FLT_MAX / 2.0f) + { + scale = -1; + absx = (absx >= FLT_MIN * 2.0f ? __scalbnf (absx, scale) : 0.0f); + absy = __scalbnf (absy, scale); + } + else if (absx < FLT_MIN && absy < FLT_MIN) { scale = FLT_MANT_DIG; - __real__ x = __scalbnf (__real__ x, scale); - __imag__ x = __scalbnf (__imag__ x, scale); + absx = __scalbnf (absx, scale); + absy = __scalbnf (absy, scale); } - d = __ieee754_hypotf (__real__ x, __imag__ x); + d = __ieee754_hypotf (absx, absy); __real__ result = __ieee754_log10f (d) - scale * M_LOG10_2f; __imag__ result = M_LOG10E * __ieee754_atan2f (__imag__ x, __real__ x); diff --git a/math/s_clog10l.c b/math/s_clog10l.c index d1fc872..3e0ceaa 100644 --- a/math/s_clog10l.c +++ b/math/s_clog10l.c @@ -43,25 +43,30 @@ __clog10l (__complex__ long double x) else if (__builtin_expect (rcls != FP_NAN && icls != FP_NAN, 1)) { /* Neither real nor imaginary part is NaN. */ + long double absx = fabsl (__real__ x), absy = fabsl (__imag__ x); long double d; int scale = 0; - if (fabsl (__real__ x) > LDBL_MAX / 2.0L - || fabsl (__imag__ x) > LDBL_MAX / 2.0L) + if (absx > LDBL_MAX / 2.0L) { scale = -1; - __real__ x = __scalbnl (__real__ x, scale); - __imag__ x = __scalbnl (__imag__ x, scale); + absx = __scalbnl (absx, scale); + absy = (absy >= LDBL_MIN * 2.0L ? __scalbnl (absy, scale) : 0.0L); } - else if (fabsl (__real__ x) < LDBL_MIN - && fabsl (__imag__ x) < LDBL_MIN) + else if (absy > LDBL_MAX / 2.0L) + { + scale = -1; + absx = (absx >= LDBL_MIN * 2.0L ? __scalbnl (absx, scale) : 0.0L); + absy = __scalbnl (absy, scale); + } + else if (absx < LDBL_MIN && absy < LDBL_MIN) { scale = LDBL_MANT_DIG; - __real__ x = __scalbnl (__real__ x, scale); - __imag__ x = __scalbnl (__imag__ x, scale); + absx = __scalbnl (absx, scale); + absy = __scalbnl (absy, scale); } - d = __ieee754_hypotl (__real__ x, __imag__ x); + d = __ieee754_hypotl (absx, absy); __real__ result = __ieee754_log10l (d) - scale * M_LOG10_2l; __imag__ result = M_LOG10El * __ieee754_atan2l (__imag__ x, __real__ x); diff --git a/math/s_clogf.c b/math/s_clogf.c index 0b27506..e20e594 100644 --- a/math/s_clogf.c +++ b/math/s_clogf.c @@ -40,25 +40,30 @@ __clogf (__complex__ float x) else if (__builtin_expect (rcls != FP_NAN && icls != FP_NAN, 1)) { /* Neither real nor imaginary part is NaN. */ + float absx = fabsf (__real__ x), absy = fabsf (__imag__ x); float d; int scale = 0; - if (fabsf (__real__ x) > FLT_MAX / 2.0f - || fabsf (__imag__ x) > FLT_MAX / 2.0f) + if (absx > FLT_MAX / 2.0f) { scale = -1; - __real__ x = __scalbnf (__real__ x, scale); - __imag__ x = __scalbnf (__imag__ x, scale); + absx = __scalbnf (absx, scale); + absy = (absy >= FLT_MIN * 2.0f ? __scalbnf (absy, scale) : 0.0f); } - else if (fabsf (__real__ x) < FLT_MIN - && fabsf (__imag__ x) < FLT_MIN) + else if (absy > FLT_MAX / 2.0f) + { + scale = -1; + absx = (absx >= FLT_MIN * 2.0f ? __scalbnf (absx, scale) : 0.0f); + absy = __scalbnf (absy, scale); + } + else if (absx < FLT_MIN && absy < FLT_MIN) { scale = FLT_MANT_DIG; - __real__ x = __scalbnf (__real__ x, scale); - __imag__ x = __scalbnf (__imag__ x, scale); + absx = __scalbnf (absx, scale); + absy = __scalbnf (absy, scale); } - d = __ieee754_hypotf (__real__ x, __imag__ x); + d = __ieee754_hypotf (absx, absy); __real__ result = __ieee754_logf (d) - scale * (float) M_LN2; __imag__ result = __ieee754_atan2f (__imag__ x, __real__ x); diff --git a/math/s_clogl.c b/math/s_clogl.c index 8968eef..a393b88 100644 --- a/math/s_clogl.c +++ b/math/s_clogl.c @@ -40,25 +40,30 @@ __clogl (__complex__ long double x) else if (__builtin_expect (rcls != FP_NAN && icls != FP_NAN, 1)) { /* Neither real nor imaginary part is NaN. */ + long double absx = fabsl (__real__ x), absy = fabsl (__imag__ x); long double d; int scale = 0; - if (fabsl (__real__ x) > LDBL_MAX / 2.0L - || fabsl (__imag__ x) > LDBL_MAX / 2.0L) + if (absx > LDBL_MAX / 2.0L) { scale = -1; - __real__ x = __scalbnl (__real__ x, scale); - __imag__ x = __scalbnl (__imag__ x, scale); + absx = __scalbnl (absx, scale); + absy = (absy >= LDBL_MIN * 2.0L ? __scalbnl (absy, scale) : 0.0L); } - else if (fabsl (__real__ x) < LDBL_MIN - && fabsl (__imag__ x) < LDBL_MIN) + else if (absy > LDBL_MAX / 2.0L) + { + scale = -1; + absx = (absx >= LDBL_MIN * 2.0L ? __scalbnl (absx, scale) : 0.0L); + absy = __scalbnl (absy, scale); + } + else if (absx < LDBL_MIN && absy < LDBL_MIN) { scale = LDBL_MANT_DIG; - __real__ x = __scalbnl (__real__ x, scale); - __imag__ x = __scalbnl (__imag__ x, scale); + absx = __scalbnl (absx, scale); + absy = __scalbnl (absy, scale); } - d = __ieee754_hypotl (__real__ x, __imag__ x); + d = __ieee754_hypotl (absx, absy); __real__ result = __ieee754_logl (d) - scale * M_LN2l; __imag__ result = __ieee754_atan2l (__imag__ x, __real__ x); -- cgit v1.1