about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog11
-rw-r--r--NEWS10
-rwxr-xr-xmath/gen-libm-test.pl10
-rw-r--r--math/libm-test.inc134
-rw-r--r--math/w_scalb.c30
-rw-r--r--math/w_scalbf.c30
-rw-r--r--math/w_scalbl.c30
7 files changed, 175 insertions, 80 deletions
diff --git a/ChangeLog b/ChangeLog
index 17d5c09f8b..22122b3323 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,16 @@
 2014-03-31  Joseph Myers  <joseph@codesourcery.com>
 
+	[BZ #6803]
+	[BZ #6804]
+	* math/w_scalb.c (__scalb): For non-SVID mode, check result and
+	set errno as appropriate.
+	* math/w_scalbf.c (__scalbf): Likewise.
+	* math/w_scalbl.c (__scalbl): Likewise.
+	* math/gen-libm-test.pl (parse_args): Handle ERRNO_PLUS_OFLOW,
+	ERRNO_MINUS_OFLOW, ERRNO_PLUS_UFLOW and ERRNO_MINUS_UFLOW.
+	* math/libm-test.inc (scalb_test_data): Add errno expectations.
+	Add more NaN tests.
+
 	[BZ #16349]
 	* math/w_atan2.c: Include <errno.h>.
 	(__atan2): Set errno for result underflowing to zero.
diff --git a/NEWS b/NEWS
index 06d137a79b..1574ab4f0c 100644
--- a/NEWS
+++ b/NEWS
@@ -9,11 +9,11 @@ Version 2.20
 
 * The following bugs are resolved with this release:
 
-  15347, 15804, 15894, 16002, 16198, 16284, 16348, 16349, 16357, 16362,
-  16447, 16532, 16545, 16574, 16599, 16600, 16609, 16610, 16611, 16613,
-  16623, 16632, 16634, 16639, 16642, 16648, 16649, 16670, 16674, 16677,
-  16680, 16683, 16689, 16695, 16701, 16706, 16707, 16712, 16713, 16714,
-  16731, 16743, 16758, 16759, 16760, 16770.
+  6804, 15347, 15804, 15894, 16002, 16198, 16284, 16348, 16349, 16357,
+  16362, 16447, 16532, 16545, 16574, 16599, 16600, 16609, 16610, 16611,
+  16613, 16623, 16632, 16634, 16639, 16642, 16648, 16649, 16670, 16674,
+  16677, 16680, 16683, 16689, 16695, 16701, 16706, 16707, 16712, 16713,
+  16714, 16731, 16743, 16758, 16759, 16760, 16770.
 
 * Running the testsuite no longer terminates as soon as a test fails.
   Instead, a file tests.sum (xtests.sum from "make xcheck") is generated,
diff --git a/math/gen-libm-test.pl b/math/gen-libm-test.pl
index 6b3a21df40..5f62872b21 100755
--- a/math/gen-libm-test.pl
+++ b/math/gen-libm-test.pl
@@ -160,6 +160,8 @@ sub parse_args {
   my ($ignore_result_any, $ignore_result_all);
   my ($num_res, @args_res, @start_rm, $rm);
   my (@plus_oflow, @minus_oflow, @plus_uflow, @minus_uflow);
+  my (@errno_plus_oflow, @errno_minus_oflow);
+  my (@errno_plus_uflow, @errno_minus_uflow);
 
   ($descr_args, $descr_res) = split /_/,$descr, 2;
 
@@ -258,6 +260,10 @@ sub parse_args {
   @minus_oflow = qw(minus_infty minus_infty -max_value -max_value);
   @plus_uflow = qw(plus_zero plus_zero plus_zero min_subnorm_value);
   @minus_uflow = qw(-min_subnorm_value minus_zero minus_zero minus_zero);
+  @errno_plus_oflow = qw(0 ERRNO_ERANGE 0 ERRNO_ERANGE);
+  @errno_minus_oflow = qw(ERRNO_ERANGE ERRNO_ERANGE 0 0);
+  @errno_plus_uflow = qw(ERRNO_ERANGE ERRNO_ERANGE ERRNO_ERANGE 0);
+  @errno_minus_uflow = qw(0 ERRNO_ERANGE ERRNO_ERANGE ERRNO_ERANGE);
   for ($rm = 0; $rm <= 3; $rm++) {
     $current_arg = $start_rm[$rm];
     $ignore_result_any = 0;
@@ -322,6 +328,10 @@ sub parse_args {
     $cline_res =~ s/minus_oflow/$minus_oflow[$rm]/g;
     $cline_res =~ s/plus_uflow/$plus_uflow[$rm]/g;
     $cline_res =~ s/minus_uflow/$minus_uflow[$rm]/g;
+    $cline_res =~ s/ERRNO_PLUS_OFLOW/$errno_plus_oflow[$rm]/g;
+    $cline_res =~ s/ERRNO_MINUS_OFLOW/$errno_minus_oflow[$rm]/g;
+    $cline_res =~ s/ERRNO_PLUS_UFLOW/$errno_plus_uflow[$rm]/g;
+    $cline_res =~ s/ERRNO_MINUS_UFLOW/$errno_minus_uflow[$rm]/g;
     $cline .= ", { $cline_res }";
   }
   print $file "    $cline },\n";
diff --git a/math/libm-test.inc b/math/libm-test.inc
index 0eff34a0ca..19194f63e9 100644
--- a/math/libm-test.inc
+++ b/math/libm-test.inc
@@ -9087,72 +9087,74 @@ round_test (void)
 
 static const struct test_ff_f_data scalb_test_data[] =
   {
-    TEST_ff_f (scalb, 2.0, 0.5, qnan_value, INVALID_EXCEPTION),
-    TEST_ff_f (scalb, 3.0, -2.5, qnan_value, INVALID_EXCEPTION),
-
-    TEST_ff_f (scalb, 0, qnan_value, qnan_value, NO_INEXACT_EXCEPTION),
-    TEST_ff_f (scalb, 1, qnan_value, qnan_value, NO_INEXACT_EXCEPTION),
-
-    TEST_ff_f (scalb, 1, 0, 1),
-    TEST_ff_f (scalb, -1, 0, -1),
-
-    TEST_ff_f (scalb, 0, plus_infty, qnan_value, INVALID_EXCEPTION),
-    TEST_ff_f (scalb, minus_zero, plus_infty, qnan_value, INVALID_EXCEPTION),
-
-    TEST_ff_f (scalb, 0, 2, 0),
-    TEST_ff_f (scalb, minus_zero, -4, minus_zero),
-    TEST_ff_f (scalb, 0, 0, 0),
-    TEST_ff_f (scalb, minus_zero, 0, minus_zero),
-    TEST_ff_f (scalb, 0, -1, 0),
-    TEST_ff_f (scalb, minus_zero, -10, minus_zero),
-    TEST_ff_f (scalb, 0, minus_infty, 0),
-    TEST_ff_f (scalb, minus_zero, minus_infty, minus_zero),
-
-    TEST_ff_f (scalb, plus_infty, -1, plus_infty),
-    TEST_ff_f (scalb, minus_infty, -10, minus_infty),
-    TEST_ff_f (scalb, plus_infty, 0, plus_infty),
-    TEST_ff_f (scalb, minus_infty, 0, minus_infty),
-    TEST_ff_f (scalb, plus_infty, 2, plus_infty),
-    TEST_ff_f (scalb, minus_infty, 100, minus_infty),
-
-    TEST_ff_f (scalb, 0.1L, minus_infty, 0.0),
-    TEST_ff_f (scalb, -0.1L, minus_infty, minus_zero),
-
-    TEST_ff_f (scalb, 1, plus_infty, plus_infty),
-    TEST_ff_f (scalb, -1, plus_infty, minus_infty),
-    TEST_ff_f (scalb, plus_infty, plus_infty, plus_infty),
-    TEST_ff_f (scalb, minus_infty, plus_infty, minus_infty),
-
-    TEST_ff_f (scalb, plus_infty, minus_infty, qnan_value, INVALID_EXCEPTION),
-    TEST_ff_f (scalb, minus_infty, minus_infty, qnan_value, INVALID_EXCEPTION),
-
-    TEST_ff_f (scalb, qnan_value, 1, qnan_value, NO_INEXACT_EXCEPTION),
-    TEST_ff_f (scalb, 1, qnan_value, qnan_value, NO_INEXACT_EXCEPTION),
-    TEST_ff_f (scalb, qnan_value, 0, qnan_value, NO_INEXACT_EXCEPTION),
-    TEST_ff_f (scalb, 0, qnan_value, qnan_value, NO_INEXACT_EXCEPTION),
-    TEST_ff_f (scalb, qnan_value, plus_infty, qnan_value, NO_INEXACT_EXCEPTION),
-    TEST_ff_f (scalb, plus_infty, qnan_value, qnan_value, NO_INEXACT_EXCEPTION),
-    TEST_ff_f (scalb, qnan_value, qnan_value, qnan_value, NO_INEXACT_EXCEPTION),
-
-    TEST_ff_f (scalb, max_value, max_value, plus_oflow, OVERFLOW_EXCEPTION),
-    TEST_ff_f (scalb, max_value, -max_value, plus_uflow, UNDERFLOW_EXCEPTION),
-    TEST_ff_f (scalb, 1, max_value, plus_oflow, OVERFLOW_EXCEPTION),
-    TEST_ff_f (scalb, 1, -max_value, plus_uflow, UNDERFLOW_EXCEPTION),
-    TEST_ff_f (scalb, min_value, max_value, plus_oflow, OVERFLOW_EXCEPTION),
-    TEST_ff_f (scalb, min_value, -max_value, plus_uflow, UNDERFLOW_EXCEPTION),
-    TEST_ff_f (scalb, min_subnorm_value, max_value, plus_oflow, OVERFLOW_EXCEPTION),
-    TEST_ff_f (scalb, min_subnorm_value, -max_value, plus_uflow, UNDERFLOW_EXCEPTION),
-    TEST_ff_f (scalb, -max_value, max_value, minus_oflow, OVERFLOW_EXCEPTION),
-    TEST_ff_f (scalb, -max_value, -max_value, minus_uflow, UNDERFLOW_EXCEPTION),
-    TEST_ff_f (scalb, -1, max_value, minus_oflow, OVERFLOW_EXCEPTION),
-    TEST_ff_f (scalb, -1, -max_value, minus_uflow, UNDERFLOW_EXCEPTION),
-    TEST_ff_f (scalb, -min_value, max_value, minus_oflow, OVERFLOW_EXCEPTION),
-    TEST_ff_f (scalb, -min_value, -max_value, minus_uflow, UNDERFLOW_EXCEPTION),
-    TEST_ff_f (scalb, -min_subnorm_value, max_value, minus_oflow, OVERFLOW_EXCEPTION),
-    TEST_ff_f (scalb, -min_subnorm_value, -max_value, minus_uflow, UNDERFLOW_EXCEPTION),
-
-    TEST_ff_f (scalb, 0.8L, 4, 12.8L),
-    TEST_ff_f (scalb, -0.854375L, 5, -27.34L),
+    TEST_ff_f (scalb, 2.0, 0.5, qnan_value, INVALID_EXCEPTION|ERRNO_EDOM),
+    TEST_ff_f (scalb, 3.0, -2.5, qnan_value, INVALID_EXCEPTION|ERRNO_EDOM),
+
+    TEST_ff_f (scalb, 0, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_ff_f (scalb, 1, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+
+    TEST_ff_f (scalb, 1, 0, 1, ERRNO_UNCHANGED),
+    TEST_ff_f (scalb, -1, 0, -1, ERRNO_UNCHANGED),
+
+    TEST_ff_f (scalb, 0, plus_infty, qnan_value, INVALID_EXCEPTION|ERRNO_EDOM),
+    TEST_ff_f (scalb, minus_zero, plus_infty, qnan_value, INVALID_EXCEPTION|ERRNO_EDOM),
+
+    TEST_ff_f (scalb, 0, 2, 0, ERRNO_UNCHANGED),
+    TEST_ff_f (scalb, minus_zero, -4, minus_zero, ERRNO_UNCHANGED),
+    TEST_ff_f (scalb, 0, 0, 0, ERRNO_UNCHANGED),
+    TEST_ff_f (scalb, minus_zero, 0, minus_zero, ERRNO_UNCHANGED),
+    TEST_ff_f (scalb, 0, -1, 0, ERRNO_UNCHANGED),
+    TEST_ff_f (scalb, minus_zero, -10, minus_zero, ERRNO_UNCHANGED),
+    TEST_ff_f (scalb, 0, minus_infty, 0, ERRNO_UNCHANGED),
+    TEST_ff_f (scalb, minus_zero, minus_infty, minus_zero, ERRNO_UNCHANGED),
+
+    TEST_ff_f (scalb, plus_infty, -1, plus_infty, ERRNO_UNCHANGED),
+    TEST_ff_f (scalb, minus_infty, -10, minus_infty, ERRNO_UNCHANGED),
+    TEST_ff_f (scalb, plus_infty, 0, plus_infty, ERRNO_UNCHANGED),
+    TEST_ff_f (scalb, minus_infty, 0, minus_infty, ERRNO_UNCHANGED),
+    TEST_ff_f (scalb, plus_infty, 2, plus_infty, ERRNO_UNCHANGED),
+    TEST_ff_f (scalb, minus_infty, 100, minus_infty, ERRNO_UNCHANGED),
+
+    TEST_ff_f (scalb, 0.1L, minus_infty, 0.0, ERRNO_UNCHANGED),
+    TEST_ff_f (scalb, -0.1L, minus_infty, minus_zero, ERRNO_UNCHANGED),
+
+    TEST_ff_f (scalb, 1, plus_infty, plus_infty, ERRNO_UNCHANGED),
+    TEST_ff_f (scalb, -1, plus_infty, minus_infty, ERRNO_UNCHANGED),
+    TEST_ff_f (scalb, plus_infty, plus_infty, plus_infty, ERRNO_UNCHANGED),
+    TEST_ff_f (scalb, minus_infty, plus_infty, minus_infty, ERRNO_UNCHANGED),
+
+    TEST_ff_f (scalb, plus_infty, minus_infty, qnan_value, INVALID_EXCEPTION|ERRNO_EDOM),
+    TEST_ff_f (scalb, minus_infty, minus_infty, qnan_value, INVALID_EXCEPTION|ERRNO_EDOM),
+
+    TEST_ff_f (scalb, qnan_value, 1, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_ff_f (scalb, 1, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_ff_f (scalb, qnan_value, 0.5, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_ff_f (scalb, 0.5, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_ff_f (scalb, qnan_value, 0, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_ff_f (scalb, 0, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_ff_f (scalb, qnan_value, plus_infty, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_ff_f (scalb, plus_infty, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_ff_f (scalb, qnan_value, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+
+    TEST_ff_f (scalb, max_value, max_value, plus_oflow, OVERFLOW_EXCEPTION|ERRNO_PLUS_OFLOW),
+    TEST_ff_f (scalb, max_value, -max_value, plus_uflow, UNDERFLOW_EXCEPTION|ERRNO_PLUS_UFLOW),
+    TEST_ff_f (scalb, 1, max_value, plus_oflow, OVERFLOW_EXCEPTION|ERRNO_PLUS_OFLOW),
+    TEST_ff_f (scalb, 1, -max_value, plus_uflow, UNDERFLOW_EXCEPTION|ERRNO_PLUS_UFLOW),
+    TEST_ff_f (scalb, min_value, max_value, plus_oflow, OVERFLOW_EXCEPTION|ERRNO_PLUS_OFLOW),
+    TEST_ff_f (scalb, min_value, -max_value, plus_uflow, UNDERFLOW_EXCEPTION|ERRNO_PLUS_UFLOW),
+    TEST_ff_f (scalb, min_subnorm_value, max_value, plus_oflow, OVERFLOW_EXCEPTION|ERRNO_PLUS_OFLOW),
+    TEST_ff_f (scalb, min_subnorm_value, -max_value, plus_uflow, UNDERFLOW_EXCEPTION|ERRNO_PLUS_UFLOW),
+    TEST_ff_f (scalb, -max_value, max_value, minus_oflow, OVERFLOW_EXCEPTION|ERRNO_MINUS_OFLOW),
+    TEST_ff_f (scalb, -max_value, -max_value, minus_uflow, UNDERFLOW_EXCEPTION|ERRNO_MINUS_UFLOW),
+    TEST_ff_f (scalb, -1, max_value, minus_oflow, OVERFLOW_EXCEPTION|ERRNO_MINUS_OFLOW),
+    TEST_ff_f (scalb, -1, -max_value, minus_uflow, UNDERFLOW_EXCEPTION|ERRNO_MINUS_UFLOW),
+    TEST_ff_f (scalb, -min_value, max_value, minus_oflow, OVERFLOW_EXCEPTION|ERRNO_MINUS_OFLOW),
+    TEST_ff_f (scalb, -min_value, -max_value, minus_uflow, UNDERFLOW_EXCEPTION|ERRNO_MINUS_UFLOW),
+    TEST_ff_f (scalb, -min_subnorm_value, max_value, minus_oflow, OVERFLOW_EXCEPTION|ERRNO_MINUS_OFLOW),
+    TEST_ff_f (scalb, -min_subnorm_value, -max_value, minus_uflow, UNDERFLOW_EXCEPTION|ERRNO_MINUS_UFLOW),
+
+    TEST_ff_f (scalb, 0.8L, 4, 12.8L, ERRNO_UNCHANGED),
+    TEST_ff_f (scalb, -0.854375L, 5, -27.34L, ERRNO_UNCHANGED),
   };
 
 static void
diff --git a/math/w_scalb.c b/math/w_scalb.c
index dbfefaf9d5..0f1e2df8ef 100644
--- a/math/w_scalb.c
+++ b/math/w_scalb.c
@@ -45,9 +45,33 @@ sysv_scalb (double x, double fn)
 double
 __scalb (double x, double fn)
 {
-  return (__builtin_expect (_LIB_VERSION == _SVID_, 0)
-	  ? sysv_scalb (x, fn)
-	  : __ieee754_scalb (x, fn));
+  if (__glibc_unlikely (_LIB_VERSION == _SVID_))
+    return sysv_scalb (x, fn);
+  else
+    {
+      double z = __ieee754_scalb (x, fn);
+
+      if (__glibc_unlikely (!__finite (z) || z == 0.0))
+	{
+	  if (__isnan (z))
+	    {
+	      if (!__isnan (x) && !__isnan (fn))
+		__set_errno (EDOM);
+	    }
+	  else if (__isinf_ns (z))
+	    {
+	      if (!__isinf_ns (x) && !__isinf_ns (fn))
+		__set_errno (ERANGE);
+	    }
+	  else
+	    {
+	      /* z == 0.  */
+	      if (x != 0.0 && !__isinf_ns (fn))
+		__set_errno (ERANGE);
+	    }
+	}
+      return z;
+    }
 }
 weak_alias (__scalb, scalb)
 #ifdef NO_LONG_DOUBLE
diff --git a/math/w_scalbf.c b/math/w_scalbf.c
index 244fd1e91b..7ab0b8a4ac 100644
--- a/math/w_scalbf.c
+++ b/math/w_scalbf.c
@@ -45,8 +45,32 @@ sysv_scalbf (float x, float fn)
 float
 __scalbf (float x, float fn)
 {
-  return (__builtin_expect (_LIB_VERSION == _SVID_, 0)
-	  ? sysv_scalbf (x, fn)
-	  : __ieee754_scalbf (x, fn));
+  if (__glibc_unlikely (_LIB_VERSION == _SVID_))
+    return sysv_scalbf (x, fn);
+  else
+    {
+      float z = __ieee754_scalbf (x, fn);
+
+      if (__glibc_unlikely (!__finitef (z) || z == 0.0f))
+	{
+	  if (__isnanf (z))
+	    {
+	      if (!__isnanf (x) && !__isnanf (fn))
+		__set_errno (EDOM);
+	    }
+	  else if (__isinf_nsf (z))
+	    {
+	      if (!__isinf_nsf (x) && !__isinf_nsf (fn))
+		__set_errno (ERANGE);
+	    }
+	  else
+	    {
+	      /* z == 0.  */
+	      if (x != 0.0f && !__isinf_nsf (fn))
+		__set_errno (ERANGE);
+	    }
+	}
+      return z;
+    }
 }
 weak_alias (__scalbf, scalbf)
diff --git a/math/w_scalbl.c b/math/w_scalbl.c
index cffaa67cc7..40cc68e865 100644
--- a/math/w_scalbl.c
+++ b/math/w_scalbl.c
@@ -45,8 +45,32 @@ sysv_scalbl (long double x, long double fn)
 long double
 __scalbl (long double x, long double fn)
 {
-  return (__builtin_expect (_LIB_VERSION == _SVID_, 0)
-	  ? sysv_scalbl (x, fn)
-	  : __ieee754_scalbl (x, fn));
+  if (__glibc_unlikely (_LIB_VERSION == _SVID_))
+    return sysv_scalbl (x, fn);
+  else
+    {
+      long double z = __ieee754_scalbl (x, fn);
+
+      if (__glibc_unlikely (!__finitel (z) || z == 0.0L))
+	{
+	  if (__isnanl (z))
+	    {
+	      if (!__isnanl (x) && !__isnanl (fn))
+		__set_errno (EDOM);
+	    }
+	  else if (__isinf_nsl (z))
+	    {
+	      if (!__isinf_nsl (x) && !__isinf_nsl (fn))
+		__set_errno (ERANGE);
+	    }
+	  else
+	    {
+	      /* z == 0.  */
+	      if (x != 0.0L && !__isinf_nsl (fn))
+		__set_errno (ERANGE);
+	    }
+	}
+      return z;
+    }
 }
 weak_alias (__scalbl, scalbl)