about summary refs log tree commit diff
path: root/sysdeps/ieee754
diff options
context:
space:
mode:
authorJoseph Myers <joseph@codesourcery.com>2012-03-28 14:57:58 +0000
committerJoseph Myers <joseph@codesourcery.com>2012-03-28 14:57:58 +0000
commitd6270972f79fe89a96fa7a3909991dad2e317033 (patch)
tree18ed157e89359cf8711d641916028dab73e37449 /sysdeps/ieee754
parent414fca039edfece0dc9bfc266730e390124687de (diff)
downloadglibc-d6270972f79fe89a96fa7a3909991dad2e317033.tar.gz
glibc-d6270972f79fe89a96fa7a3909991dad2e317033.tar.xz
glibc-d6270972f79fe89a96fa7a3909991dad2e317033.zip
Fix pow of negative numbers to integer exponents (bugs 369, 2678, 3866).
Diffstat (limited to 'sysdeps/ieee754')
-rw-r--r--sysdeps/ieee754/k_standard.c54
1 files changed, 53 insertions, 1 deletions
diff --git a/sysdeps/ieee754/k_standard.c b/sysdeps/ieee754/k_standard.c
index c3326d9ef5..4e65bb16ce 100644
--- a/sysdeps/ieee754/k_standard.c
+++ b/sysdeps/ieee754/k_standard.c
@@ -508,6 +508,9 @@ __kernel_standard(double x, double y, int type)
 		exc.type = UNDERFLOW;
 		exc.name = type < 100 ? "pow" : (type < 200 ? "powf" : "powl");
 		exc.retval =  zero;
+		y *= 0.5;
+		if (x < zero && __rint (y) != y)
+		  exc.retval = -zero;
 		if (_LIB_VERSION == _POSIX_)
 		  __set_errno (ERANGE);
 		else if (!matherr(&exc)) {
@@ -1004,6 +1007,8 @@ long double
 __kernel_standard_l (long double x, long double y, int type)
 {
   double dx, dy;
+  struct exception exc;
+
   if (isfinite (x))
     {
       long double ax = fabsl (x);
@@ -1028,5 +1033,52 @@ __kernel_standard_l (long double x, long double y, int type)
     }
   else
     dy = y;
-  return __kernel_standard (dx, dy, type);
+
+  switch (type)
+    {
+    case 221:
+      /* powl (x, y) overflow.  */
+      exc.arg1 = dx;
+      exc.arg2 = dy;
+      exc.type = OVERFLOW;
+      exc.name = "powl";
+      if (_LIB_VERSION == _SVID_)
+	{
+	  exc.retval = HUGE;
+	  y *= 0.5;
+	  if (x < zero && __rintl (y) != y)
+	    exc.retval = -HUGE;
+	}
+      else
+	{
+	  exc.retval = HUGE_VAL;
+	  y *= 0.5;
+	  if (x < zero && __rintl (y) != y)
+	    exc.retval = -HUGE_VAL;
+	}
+      if (_LIB_VERSION == _POSIX_)
+	__set_errno (ERANGE);
+      else if (!matherr (&exc))
+	__set_errno (ERANGE);
+      return exc.retval;
+
+    case 222:
+      /* powl (x, y) underflow.  */
+      exc.arg1 = dx;
+      exc.arg2 = dy;
+      exc.type = UNDERFLOW;
+      exc.name = "powl";
+      exc.retval = zero;
+      y *= 0.5;
+      if (x < zero && __rintl (y) != y)
+	exc.retval = -zero;
+      if (_LIB_VERSION == _POSIX_)
+	__set_errno (ERANGE);
+      else if (!matherr (&exc))
+	__set_errno (ERANGE);
+      return exc.retval;
+
+    default:
+      return __kernel_standard (dx, dy, type);
+    }
 }