summaryrefslogtreecommitdiff
path: root/math
diff options
context:
space:
mode:
authorJoseph Myers <joseph@codesourcery.com>2012-03-14 11:53:32 +0000
committerJoseph Myers <joseph@codesourcery.com>2012-03-14 11:53:32 +0000
commite456826d7a539fb322bb9719297bd386eded8e32 (patch)
tree5a0b1e8979b004c88796e199fac827a0d8817207 /math
parent6278569b6c1ee1b6e2b36af059e699233da0b88b (diff)
Fix csqrt overflow/underflow (bug 13841).
Diffstat (limited to 'math')
-rw-r--r--math/libm-test.inc18
-rw-r--r--math/s_csqrt.c26
-rw-r--r--math/s_csqrtf.c26
-rw-r--r--math/s_csqrtl.c26
4 files changed, 90 insertions, 6 deletions
diff --git a/math/libm-test.inc b/math/libm-test.inc
index 191f35959b..caa3ba414d 100644
--- a/math/libm-test.inc
+++ b/math/libm-test.inc
@@ -2657,6 +2657,24 @@ csqrt_test (void)
part). */
TEST_c_c (csqrt, 0, -1, M_SQRT_2_2, -M_SQRT_2_2);
+ TEST_c_c (csqrt, 0x1.fffffep+127L, 0x1.fffffep+127L, 2.026714405498316804978751017492482558075e+19L, 8.394925938143272988211878516208015586281e+18L);
+ TEST_c_c (csqrt, 0x1.fffffep+127L, 1.0L, 1.844674352395372953599975585936590505260e+19L, 2.710505511993121390769065968615872097053e-20L);
+ TEST_c_c (csqrt, 0x1p-149L, 0x1p-149L, 4.112805464342778798097003462770175200803e-23L, 1.703579802732953750368659735601389709551e-23L);
+ TEST_c_c (csqrt, 0x1p-147L, 0x1p-147L, 8.225610928685557596194006925540350401606e-23L, 3.407159605465907500737319471202779419102e-23L);
+
+#ifndef TEST_FLOAT
+ TEST_c_c (csqrt, 0x1.fffffffffffffp+1023L, 0x1.fffffffffffffp+1023L, 1.473094556905565378990473658199034571917e+154L, 6.101757441282702188537080005372547713595e+153L);
+ TEST_c_c (csqrt, 0x1.fffffffffffffp+1023L, 0x1p+1023L, 1.379778091031440685006200821918878702861e+154L, 3.257214233483129514781233066898042490248e+153L);
+ TEST_c_c (csqrt, 0x1p-1074L, 0x1p-1074L, 2.442109726130830256743814843868934877597e-162L, 1.011554969366634726113090867589031782487e-162L);
+ TEST_c_c (csqrt, 0x1p-1073L, 0x1p-1073L, 3.453664695497464982856905711457966660085e-162L, 1.430554756764195530630723976279903095110e-162L);
+#endif
+
+#if defined TEST_LDOUBLE && LDBL_MAX_EXP >= 16384
+ TEST_c_c (csqrt, 0x1.fp+16383L, 0x1.fp+16383L, 1.179514222452201722651836720466795901016e+2466L, 4.885707879516577666702435054303191575148e+2465L);
+ TEST_c_c (csqrt, 0x1.fp+16383L, 0x1p+16383L, 1.106698967236475180613254276996359485630e+2466L, 2.687568007603946993388538156299100955642e+2465L);
+ TEST_c_c (csqrt, 0x1p-16440L, 0x1p-16441L, 3.514690655930285351254618340783294558136e-2475L, 8.297059146828716918029689466551384219370e-2476L);
+#endif
+
END (csqrt, complex);
}
diff --git a/math/s_csqrt.c b/math/s_csqrt.c
index 76585e889c..002ea5fdc2 100644
--- a/math/s_csqrt.c
+++ b/math/s_csqrt.c
@@ -1,5 +1,5 @@
/* Complex square root of double value.
- Copyright (C) 1997, 1998, 2005, 2011 Free Software Foundation, Inc.
+ Copyright (C) 1997-2012 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Based on an algorithm by Stephen L. Moshier <moshier@world.std.com>.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
@@ -21,7 +21,7 @@
#include <complex.h>
#include <math.h>
#include <math_private.h>
-
+#include <float.h>
__complex__ double
__csqrt (__complex__ double x)
@@ -83,6 +83,22 @@ __csqrt (__complex__ double x)
else
{
double d, r, s;
+ int scale = 0;
+
+ if (fabs (__real__ x) > DBL_MAX / 2.0
+ || fabs (__imag__ x) > DBL_MAX / 2.0)
+ {
+ scale = 1;
+ __real__ x = __scalbn (__real__ x, -2 * scale);
+ __imag__ x = __scalbn (__imag__ x, -2 * scale);
+ }
+ else if (fabs (__real__ x) < DBL_MIN
+ && fabs (__imag__ x) < DBL_MIN)
+ {
+ scale = -(DBL_MANT_DIG / 2);
+ __real__ x = __scalbn (__real__ x, -2 * scale);
+ __imag__ x = __scalbn (__imag__ x, -2 * scale);
+ }
d = __ieee754_hypot (__real__ x, __imag__ x);
/* Use the identity 2 Re res Im res = Im x
@@ -98,6 +114,12 @@ __csqrt (__complex__ double x)
r = fabs ((0.5 * __imag__ x) / s);
}
+ if (scale)
+ {
+ r = __scalbn (r, scale);
+ s = __scalbn (s, scale);
+ }
+
__real__ res = r;
__imag__ res = __copysign (s, __imag__ x);
}
diff --git a/math/s_csqrtf.c b/math/s_csqrtf.c
index d9949c685b..6539ba2249 100644
--- a/math/s_csqrtf.c
+++ b/math/s_csqrtf.c
@@ -1,5 +1,5 @@
/* Complex square root of float value.
- Copyright (C) 1997, 1998, 2005, 2011 Free Software Foundation, Inc.
+ Copyright (C) 1997-2012 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Based on an algorithm by Stephen L. Moshier <moshier@world.std.com>.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
@@ -21,7 +21,7 @@
#include <complex.h>
#include <math.h>
#include <math_private.h>
-
+#include <float.h>
__complex__ float
__csqrtf (__complex__ float x)
@@ -83,6 +83,22 @@ __csqrtf (__complex__ float x)
else
{
float d, r, s;
+ int scale = 0;
+
+ if (fabsf (__real__ x) > FLT_MAX / 2.0f
+ || fabsf (__imag__ x) > FLT_MAX / 2.0f)
+ {
+ scale = 1;
+ __real__ x = __scalbnf (__real__ x, -2 * scale);
+ __imag__ x = __scalbnf (__imag__ x, -2 * scale);
+ }
+ else if (fabsf (__real__ x) < FLT_MIN
+ && fabsf (__imag__ x) < FLT_MIN)
+ {
+ scale = -(FLT_MANT_DIG / 2);
+ __real__ x = __scalbnf (__real__ x, -2 * scale);
+ __imag__ x = __scalbnf (__imag__ x, -2 * scale);
+ }
d = __ieee754_hypotf (__real__ x, __imag__ x);
/* Use the identity 2 Re res Im res = Im x
@@ -98,6 +114,12 @@ __csqrtf (__complex__ float x)
r = fabsf ((0.5f * __imag__ x) / s);
}
+ if (scale)
+ {
+ r = __scalbnf (r, scale);
+ s = __scalbnf (s, scale);
+ }
+
__real__ res = r;
__imag__ res = __copysignf (s, __imag__ x);
}
diff --git a/math/s_csqrtl.c b/math/s_csqrtl.c
index 0c624c7a73..64332f67b2 100644
--- a/math/s_csqrtl.c
+++ b/math/s_csqrtl.c
@@ -1,5 +1,5 @@
/* Complex square root of long double value.
- Copyright (C) 1997, 1998, 2005, 2011 Free Software Foundation, Inc.
+ Copyright (C) 1997-2012 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Based on an algorithm by Stephen L. Moshier <moshier@world.std.com>.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
@@ -21,7 +21,7 @@
#include <complex.h>
#include <math.h>
#include <math_private.h>
-
+#include <float.h>
__complex__ long double
__csqrtl (__complex__ long double x)
@@ -83,6 +83,22 @@ __csqrtl (__complex__ long double x)
else
{
long double d, r, s;
+ int scale = 0;
+
+ if (fabsl (__real__ x) > LDBL_MAX / 2.0L
+ || fabsl (__imag__ x) > LDBL_MAX / 2.0L)
+ {
+ scale = 1;
+ __real__ x = __scalbnl (__real__ x, -2 * scale);
+ __imag__ x = __scalbnl (__imag__ x, -2 * scale);
+ }
+ else if (fabsl (__real__ x) < LDBL_MIN
+ && fabsl (__imag__ x) < LDBL_MIN)
+ {
+ scale = -(LDBL_MANT_DIG / 2);
+ __real__ x = __scalbnl (__real__ x, -2 * scale);
+ __imag__ x = __scalbnl (__imag__ x, -2 * scale);
+ }
d = __ieee754_hypotl (__real__ x, __imag__ x);
/* Use the identity 2 Re res Im res = Im x
@@ -98,6 +114,12 @@ __csqrtl (__complex__ long double x)
r = fabsl ((0.5L * __imag__ x) / s);
}
+ if (scale)
+ {
+ r = __scalbnl (r, scale);
+ s = __scalbnl (s, scale);
+ }
+
__real__ res = r;
__imag__ res = __copysignl (s, __imag__ x);
}