about summary refs log tree commit diff
path: root/math
diff options
context:
space:
mode:
authorThomas Schwinge <thomas@codesourcery.com>2013-04-02 13:51:02 +0200
committerThomas Schwinge <thomas@codesourcery.com>2013-04-02 13:51:02 +0200
commit572676160d5639edc0ecb663147bd291841458d1 (patch)
tree26abea75b21e81f568075075249aa3dbedad20c7 /math
parent60c414c346a1d5ef0510ffbdc0ab75f288ee4d3f (diff)
downloadglibc-572676160d5639edc0ecb663147bd291841458d1.tar.gz
glibc-572676160d5639edc0ecb663147bd291841458d1.tar.xz
glibc-572676160d5639edc0ecb663147bd291841458d1.zip
New <math.h> macro named issignaling to check for a signaling NaN (sNaN).
It is based on draft TS 18661 and currently enabled as a GNU extension.
Diffstat (limited to 'math')
-rw-r--r--math/Makefile2
-rw-r--r--math/Versions3
-rw-r--r--math/basic-test.c65
-rw-r--r--math/bits/mathcalls.h6
-rwxr-xr-xmath/gen-libm-test.pl2
-rw-r--r--math/libm-test.inc56
-rw-r--r--math/math.h14
-rw-r--r--math/test-snan.c44
8 files changed, 177 insertions, 15 deletions
diff --git a/math/Makefile b/math/Makefile
index e216dfb96a..f396ba206a 100644
--- a/math/Makefile
+++ b/math/Makefile
@@ -58,7 +58,7 @@ libm-calls = e_acos e_acosh e_asin e_atan2 e_atanh e_cosh e_exp e_fmod	\
 	     s_catan s_casin s_ccos s_csin s_ctan s_ctanh s_cacos	\
 	     s_casinh s_cacosh s_catanh s_csqrt s_cpow s_cproj s_clog10 \
 	     s_fma s_lrint s_llrint s_lround s_llround e_exp10 w_log2	\
-	     s_isinf_ns $(calls:s_%=m_%) x2y2m1 k_casinh
+	     s_isinf_ns s_issignaling $(calls:s_%=m_%) x2y2m1 k_casinh
 
 include ../Makeconfig
 
diff --git a/math/Versions b/math/Versions
index 09888510b1..513ab14244 100644
--- a/math/Versions
+++ b/math/Versions
@@ -198,4 +198,7 @@ libm {
     __gamma_r_finite; __gammaf_r_finite; __gammal_r_finite;
     __exp_finite; __expf_finite; __expl_finite;
   }
+  GLIBC_2.18 {
+    __issignaling; __issignalingf; __issignalingl;
+  }
 }
diff --git a/math/basic-test.c b/math/basic-test.c
index ffead2ec0f..9e9b848ee5 100644
--- a/math/basic-test.c
+++ b/math/basic-test.c
@@ -20,6 +20,9 @@
 #include <float.h>
 #include <stdio.h>
 
+#include <math-tests.h>
+
+
 static int errors = 0;
 
 
@@ -39,6 +42,10 @@ NAME (void)								      \
   /* Variables are declared volatile to forbid some compiler		      \
      optimizations.  */							      \
   volatile FLOAT Inf_var, qNaN_var, zero_var, one_var;			      \
+  /* A sNaN is only guaranteed to be representable in variables with */	      \
+  /* static (or thread-local) storage duration.  */			      \
+  static volatile FLOAT sNaN_var = __builtin_nans ## SUFFIX ("");	      \
+  static volatile FLOAT minus_sNaN_var = -__builtin_nans ## SUFFIX ("");      \
   FLOAT x1, x2;								      \
 									      \
   zero_var = 0.0;							      \
@@ -49,6 +56,8 @@ NAME (void)								      \
   (void) &zero_var;							      \
   (void) &one_var;							      \
   (void) &qNaN_var;							      \
+  (void) &sNaN_var;							      \
+  (void) &minus_sNaN_var;						      \
   (void) &Inf_var;							      \
 									      \
 									      \
@@ -56,16 +65,41 @@ NAME (void)								      \
   check (#FLOAT " isinf (-inf) == -1", isinf (-Inf_var) == -1);		      \
   check (#FLOAT " !isinf (1)", !(isinf (one_var)));			      \
   check (#FLOAT " !isinf (qNaN)", !(isinf (qNaN_var)));			      \
+  if (SNAN_TESTS (FLOAT))						      \
+    check (#FLOAT " !isinf (sNaN)", !(isinf (sNaN_var)));		      \
 									      \
   check (#FLOAT " isnan (qNaN)", isnan (qNaN_var));			      \
+  if (SNAN_TESTS (FLOAT))						      \
+    check (#FLOAT " isnan (sNaN)", isnan (sNaN_var));			      \
   check (#FLOAT " isnan (-qNaN)", isnan (-qNaN_var));			      \
+  if (SNAN_TESTS (FLOAT))						      \
+    check (#FLOAT " isnan (-sNaN)", isnan (minus_sNaN_var));		      \
   check (#FLOAT " !isnan (1)", !(isnan (one_var)));			      \
   check (#FLOAT " !isnan (inf)", !(isnan (Inf_var)));			      \
 									      \
+  check (#FLOAT " !issignaling (qNaN)", !(issignaling (qNaN_var)));	      \
+  if (SNAN_TESTS (FLOAT))						      \
+    check (#FLOAT " issignaling (sNaN)", issignaling (sNaN_var));	      \
+  check (#FLOAT " !issignaling (-qNaN)", !(issignaling (-qNaN_var)));	      \
+  if (SNAN_TESTS (FLOAT))						      \
+    check (#FLOAT " issignaling (-sNaN)", issignaling (minus_sNaN_var));      \
+  check (#FLOAT " !issignaling (1)", !(issignaling (one_var)));		      \
+  check (#FLOAT " !issignaling (inf)", !(issignaling (Inf_var)));	      \
+									      \
   check (#FLOAT " inf == inf", Inf_var == Inf_var);			      \
   check (#FLOAT " -inf == -inf", -Inf_var == -Inf_var);			      \
   check (#FLOAT " inf != -inf", Inf_var != -Inf_var);			      \
   check (#FLOAT " qNaN != qNaN", qNaN_var != qNaN_var);			      \
+  if (SNAN_TESTS (FLOAT))						      \
+    check (#FLOAT " sNaN != sNaN", sNaN_var != sNaN_var);		      \
+  if (SNAN_TESTS (FLOAT))						      \
+    check (#FLOAT " qNaN != sNaN", qNaN_var != sNaN_var);		      \
+  if (SNAN_TESTS (FLOAT))						      \
+    check (#FLOAT " -sNaN != -sNaN", minus_sNaN_var != minus_sNaN_var);	      \
+  if (SNAN_TESTS (FLOAT))						      \
+    check (#FLOAT " sNaN != -sNaN", sNaN_var != minus_sNaN_var);	      \
+  if (SNAN_TESTS (FLOAT))						      \
+    check (#FLOAT " qNaN != -sNaN", qNaN_var != minus_sNaN_var);	      \
 									      \
   /*									      \
      the same tests but this time with NAN from <bits/nan.h>		      \
@@ -76,6 +110,11 @@ NAME (void)								      \
   check (#FLOAT " !isinf (NAN)", !(isinf (NAN)));			      \
   check (#FLOAT " !isinf (-NAN)", !(isinf (-NAN)));			      \
   check (#FLOAT " NAN != NAN", NAN != NAN);				      \
+  check (#FLOAT " NAN != qNaN", NAN != qNaN_var);			      \
+  if (SNAN_TESTS (FLOAT))						      \
+    check (#FLOAT " NAN != sNaN", NAN != sNaN_var);			      \
+  if (SNAN_TESTS (FLOAT))						      \
+    check (#FLOAT " NAN != -sNaN", NAN != minus_sNaN_var);		      \
 									      \
   /*									      \
      And again with the value returned by the `nan' function.		      \
@@ -86,6 +125,12 @@ NAME (void)								      \
   check (#FLOAT " !isinf (-nan (\"\"))", !(isinf (-nan ## SUFFIX (""))));     \
   check (#FLOAT " nan (\"\") != nan (\"\")",				      \
 	 nan ## SUFFIX ("") != nan ## SUFFIX (""));			      \
+  check (#FLOAT " nan (\"\") != qNaN", nan ## SUFFIX ("") != qNaN_var);	      \
+  if (SNAN_TESTS (FLOAT))						      \
+    check (#FLOAT " nan (\"\") != sNaN", nan ## SUFFIX ("") != sNaN_var);     \
+  if (SNAN_TESTS (FLOAT))						      \
+    check (#FLOAT " nan (\"\") != -sNaN",				      \
+	   nan ## SUFFIX ("") != minus_sNaN_var);			      \
 									      \
   /* test if EPSILON is ok */						      \
   x1 = 1.0;								      \
@@ -108,6 +153,9 @@ void									      \
 NAME (void)								      \
 {									      \
   volatile DOUBLE Inf_var, qNaN_var, zero_var, one_var;			      \
+  /* A sNaN is only guaranteed to be representable in variables with */	      \
+  /* static (or thread-local) storage duration.  */			      \
+  static volatile DOUBLE sNaN_var = __builtin_nans ## SUFFIX ("");	      \
   FLOAT x1, x2;								      \
 									      \
   zero_var = 0.0;							      \
@@ -116,10 +164,25 @@ NAME (void)								      \
   Inf_var = one_var / zero_var;						      \
 									      \
   (void) &qNaN_var;							      \
+  (void) &sNaN_var;							      \
   (void) &Inf_var;							      \
 									      \
   x1 = (FLOAT) qNaN_var;						      \
-  check (" "#FLOAT" x = ("#FLOAT") ("#DOUBLE") qNaN", isnan (x1) != 0);	      \
+  check (" "#FLOAT" x = ("#FLOAT") ("#DOUBLE") qNaN, isnan", isnan (x1));     \
+  check (" "#FLOAT" x = ("#FLOAT") ("#DOUBLE") qNaN, !issignaling",	      \
+	 !issignaling (x1));						      \
+  if (SNAN_TESTS (FLOAT))						      \
+    {									      \
+      x1 = (FLOAT) sNaN_var;						      \
+      check (" "#FLOAT" x = ("#FLOAT") ("#DOUBLE") sNaN, isnan", isnan (x1)); \
+      if (SNAN_TESTS_TYPE_CAST)						      \
+	{								      \
+	  /* Upon type conversion, a sNaN is converted into a qNaN plus an */ \
+	  /* INVALID exception (not checked here).  */			      \
+	  check (" "#FLOAT" x = ("#FLOAT") ("#DOUBLE") sNaN, !issignaling",   \
+		 !issignaling (x1));					      \
+	}								      \
+      }									      \
   x2 = (FLOAT) Inf_var;							      \
   check (" "#FLOAT" x = ("#FLOAT") ("#DOUBLE") Inf", isinf (x2) != 0);	      \
 }
diff --git a/math/bits/mathcalls.h b/math/bits/mathcalls.h
index e5af507257..870c54c529 100644
--- a/math/bits/mathcalls.h
+++ b/math/bits/mathcalls.h
@@ -360,6 +360,12 @@ __MATHCALL (fma,, (_Mdouble_ __x, _Mdouble_ __y, _Mdouble_ __z));
 __END_NAMESPACE_C99
 #endif
 
+#ifdef __USE_GNU
+/* Test for signaling NaN.  */
+__MATHDECL_1 (int, __issignaling,, (_Mdouble_ __value))
+     __attribute__ ((__const__));
+#endif
+
 #if defined __USE_MISC || defined __USE_XOPEN_EXTENDED
 /* Return X times (2 to the Nth power).  */
 __MATHCALL (scalb,, (_Mdouble_ __x, _Mdouble_ __n));
diff --git a/math/gen-libm-test.pl b/math/gen-libm-test.pl
index f50f1d9e02..aa60d9dbae 100755
--- a/math/gen-libm-test.pl
+++ b/math/gen-libm-test.pl
@@ -322,7 +322,7 @@ sub parse_args {
   }
   # Special handling for some macros:
   $cline .= " (\"$str\", ";
-  if ($args[0] =~ /fpclassify|isnormal|isfinite|isinf|isnan|signbit
+  if ($args[0] =~ /fpclassify|isnormal|isfinite|isinf|isnan|issignaling|signbit
       |isgreater|isgreaterequal|isless|islessequal
       |islessgreater|isunordered/x) {
     $c_call = "$args[0] (";
diff --git a/math/libm-test.inc b/math/libm-test.inc
index 3c5e58f39f..1d3ba48b7d 100644
--- a/math/libm-test.inc
+++ b/math/libm-test.inc
@@ -42,7 +42,7 @@
    cbrt, ceil, copysign, cos, cosh, erf, erfc, exp, exp10, exp2, expm1,
    fabs, fdim, finite, floor, fma, fmax, fmin, fmod, fpclassify,
    frexp, gamma, hypot,
-   ilogb, isfinite, isinf, isnan, isnormal,
+   ilogb, isfinite, isinf, isnan, isnormal, issignaling,
    isless, islessequal, isgreater, isgreaterequal, islessgreater, isunordered,
    j0, j1, jn,
    ldexp, lgamma, log, log10, log1p, log2, logb,
@@ -87,9 +87,8 @@
    aren't checked at the moment.
 
    NaN values: There exist signalling and quiet NaNs.  This implementation
-   only uses quiet NaN as parameter but does not differentiate
-   between the two kinds of NaNs as result.  Where the sign of a NaN is
-   significant, this is not tested.
+   only uses quiet NaN as parameter.  Where the sign of a NaN is
+   significant, this is not tested.  The payload of NaNs is not examined.
 
    Inline functions: Inlining functions should give an improvement in
    speed - but not in precission.  The inlined functions return
@@ -265,6 +264,19 @@ set_max_error (FLOAT current, FLOAT *curr_max_error)
 }
 
 
+/* Print a FLOAT.  */
+static void
+print_float (FLOAT f)
+{
+  /* As printf doesn't differ between a sNaN and a qNaN, do this manually.  */
+  if (issignaling (f))
+    printf ("sNaN\n");
+  else if (isnan (f))
+    printf ("qNaN\n");
+  else
+    printf ("% .20" PRINTF_EXPR "  % .20" PRINTF_XEXPR "\n", f, f);
+}
+
 /* Should the message print to screen?  This depends on the verbose flag,
    and the test status.  */
 static int
@@ -534,7 +546,11 @@ check_float_internal (const char *test_name, FLOAT computed, FLOAT expected,
   FLOAT ulp = 0;
 
   test_exceptions (test_name, exceptions);
-  if (isnan (computed) && isnan (expected))
+  if (issignaling (computed) && issignaling (expected))
+    ok = 1;
+  else if (issignaling (computed) || issignaling (expected))
+    ok = 0;
+  else if (isnan (computed) && isnan (expected))
     ok = 1;
   else if (isinf (computed) && isinf (expected))
     {
@@ -548,8 +564,9 @@ check_float_internal (const char *test_name, FLOAT computed, FLOAT expected,
       else
 	ok = 1;
     }
-  /* Don't calc ulp for NaNs or infinities.  */
-  else if (isinf (computed) || isnan (computed) || isinf (expected) || isnan (expected))
+  /* Don't calculate ULPs for infinities or any kind of NaNs.  */
+  else if (isinf (computed) || isnan (computed)
+	   || isinf (expected) || isnan (expected))
     ok = 0;
   else
     {
@@ -594,10 +611,10 @@ check_float_internal (const char *test_name, FLOAT computed, FLOAT expected,
 	printf ("Failure: ");
       printf ("Test: %s\n", test_name);
       printf ("Result:\n");
-      printf (" is:         % .20" PRINTF_EXPR "  % .20" PRINTF_XEXPR "\n",
-	      computed, computed);
-      printf (" should be:  % .20" PRINTF_EXPR "  % .20" PRINTF_XEXPR "\n",
-	      expected, expected);
+      printf (" is:         ");
+      print_float (computed);
+      printf (" should be:  ");
+      print_float (expected);
       if (print_diff)
 	{
 	  printf (" difference: % .20" PRINTF_EXPR "  % .20" PRINTF_XEXPR
@@ -7813,6 +7830,22 @@ isnormal_test (void)
 }
 
 static void
+issignaling_test (void)
+{
+  START (issignaling);
+
+  TEST_f_b (issignaling, 0, 0);
+  TEST_f_b (issignaling, minus_zero, 0);
+  TEST_f_b (issignaling, 10, 0);
+  TEST_f_b (issignaling, min_subnorm_value, 0);
+  TEST_f_b (issignaling, plus_infty, 0);
+  TEST_f_b (issignaling, minus_infty, 0);
+  TEST_f_b (issignaling, qnan_value, 0);
+
+  END (issignaling);
+}
+
+static void
 isunordered_test (void)
 {
   START (isunordered);
@@ -12448,6 +12481,7 @@ main (int argc, char **argv)
   isinf_test ();
   isnan_test ();
   isnormal_test ();
+  issignaling_test ();
   signbit_test ();
 
   /* Trigonometric functions:  */
diff --git a/math/math.h b/math/math.h
index 2f25c237d4..e3adf096ad 100644
--- a/math/math.h
+++ b/math/math.h
@@ -282,6 +282,20 @@ enum
 
 #endif /* Use ISO C99.  */
 
+#ifdef __USE_GNU
+/* Return nonzero value if X is a signaling NaN.  */
+# ifdef __NO_LONG_DOUBLE_MATH
+#  define issignaling(x) \
+     (sizeof (x) == sizeof (float) ? __issignalingf (x) : __issignaling (x))
+# else
+#  define issignaling(x) \
+     (sizeof (x) == sizeof (float)					      \
+      ? __issignalingf (x)						      \
+      : sizeof (x) == sizeof (double)					      \
+      ? __issignaling (x) : __issignalingl (x))
+# endif
+#endif /* Use GNU.  */
+
 #ifdef	__USE_MISC
 /* Support for various different standard error handling behaviors.  */
 typedef enum
diff --git a/math/test-snan.c b/math/test-snan.c
index f185cbb45c..82f1dbe209 100644
--- a/math/test-snan.c
+++ b/math/test-snan.c
@@ -1,4 +1,4 @@
-/* Test signaling NaNs in isnan, isinf, and similar functions.
+/* Test signaling NaNs in issignaling, isnan, isinf, and similar functions.
    Copyright (C) 2008-2013 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Andreas Jaeger <aj@suse.de>, 2005.
@@ -119,6 +119,48 @@ NAME (void)								      \
   feenableexcept (FE_ALL_EXCEPT);					      \
   if (sigsetjmp(sigfpe_buf, 0))						      \
     {									      \
+      printf (#FLOAT " issignaling (qNaN) raised SIGFPE\n");		      \
+      errors++;								      \
+    } else {								      \
+      check (#FLOAT " issignaling (qNaN)", !issignaling (qNaN_var));	      \
+    }									      \
+									      \
+  feclearexcept(FE_ALL_EXCEPT);						      \
+  feenableexcept (FE_ALL_EXCEPT);					      \
+  if (sigsetjmp(sigfpe_buf, 0))						      \
+    {									      \
+      printf (#FLOAT " issignaling (-qNaN) raised SIGFPE\n");		      \
+      errors++;								      \
+    } else {								      \
+      check (#FLOAT " issignaling (-qNaN)", !issignaling (-qNaN_var));	      \
+    }									      \
+									      \
+  feclearexcept(FE_ALL_EXCEPT);						      \
+  feenableexcept (FE_ALL_EXCEPT);					      \
+  if (sigsetjmp(sigfpe_buf, 0))						      \
+    {									      \
+      printf (#FLOAT " issignaling (sNaN) raised SIGFPE\n");		      \
+      errors++;								      \
+    } else {								      \
+      check (#FLOAT " issignaling (sNaN)",				      \
+	     SNAN_TESTS (FLOAT) ? issignaling (sNaN_var) : 1);		      \
+    }									      \
+									      \
+  feclearexcept(FE_ALL_EXCEPT);						      \
+  feenableexcept (FE_ALL_EXCEPT);					      \
+  if (sigsetjmp(sigfpe_buf, 0))						      \
+    {									      \
+      printf (#FLOAT " issignaling (-sNaN) raised SIGFPE\n");		      \
+      errors++;								      \
+    } else {								      \
+      check (#FLOAT " issignaling (-sNaN)",				      \
+	     SNAN_TESTS (FLOAT) ? issignaling (minus_sNaN_var) : 1);	      \
+    }									      \
+									      \
+  feclearexcept(FE_ALL_EXCEPT);						      \
+  feenableexcept (FE_ALL_EXCEPT);					      \
+  if (sigsetjmp(sigfpe_buf, 0))						      \
+    {									      \
       printf (#FLOAT " isnan (qNaN) raised SIGFPE\n");			      \
       errors++;								      \
     } else {								      \