]> sourceware.org Git - glibc.git/commitdiff
Set errno for scalb errors (bug 6803, bug 6804).
authorJoseph Myers <joseph@codesourcery.com>
Mon, 31 Mar 2014 14:57:53 +0000 (14:57 +0000)
committerJoseph Myers <joseph@codesourcery.com>
Mon, 31 Mar 2014 14:57:53 +0000 (14:57 +0000)
This patch fixes the default mode of scalb to set errno (bugs 6803 and
6804).

Previously, the _LIB_VERSION == _SVID_ mode would set errno but only
in some relevant cases, and with various peculiarities (such as errno
setting when an exact infinity or zero result arises with an argument
to scalb being an infinity).  This patch leaves this mode
bug-compatible, while making the default mode set errno in accordance
with normal practice (so an exact infinity from an infinite argument
is not an error, and nor is an exact zero result).  gen-libm-test.pl
is taught new notation such as ERRNO_PLUS_OFLOW to facilitate writing
the tests of errno setting for underflow / overflow in libm-test.inc.

Note that bug 6803 also covers scalbn and scalbln, but this patch only
addresses the scalb parts of that bug (along with the whole of bug
6804).

Tested x86_64 and x86.

[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.

ChangeLog
NEWS
math/gen-libm-test.pl
math/libm-test.inc
math/w_scalb.c
math/w_scalbf.c
math/w_scalbl.c

index 17d5c09f8bd19682d7a34dbdcd0b853d763acb04..22122b3323acaf195a22c27e891eaf714d5e716d 100644 (file)
--- 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 06d137a79b878490a8f6cb570a15a78db0bd21ad..1574ab4f0cf8e55115fac9009a525182f4f65a99 100644 (file)
--- 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,
index 6b3a21df40df1fd4a90a609de9db76a47920ab4e..5f62872b213805e7781f22a9b20b711b0bb5f54e 100755 (executable)
@@ -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";
index 0eff34a0cab886269d723c91e2419f928800d836..19194f63e9e07577f2501783ba5cebf5ed360c4c 100644 (file)
@@ -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
index dbfefaf9d5ed4546baff7e4b01ed0bcbf2ae0246..0f1e2df8ef1d14e9db63a89cb951b5a3a6199922 100644 (file)
@@ -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
index 244fd1e91b685daad4fc907f2ea1cdfa191fa6b0..7ab0b8a4acda1905dfb8bc664e5c96fb78d9b17d 100644 (file)
@@ -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)
index cffaa67cc7fb75d9b33d0474051d3d9e158ce4d3..40cc68e8657554c21a0917693097c57c11540ae8 100644 (file)
@@ -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)
This page took 0.136006 seconds and 5 git commands to generate.