summaryrefslogtreecommitdiff
path: root/lib/isnan.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/isnan.c')
-rw-r--r--lib/isnan.c46
1 files changed, 31 insertions, 15 deletions
diff --git a/lib/isnan.c b/lib/isnan.c
index a59dea79..d70c9348 100644
--- a/lib/isnan.c
+++ b/lib/isnan.c
@@ -1,5 +1,5 @@
/* Test for NaN that does not need libm.
- Copyright (C) 2007-2010 Free Software Foundation, Inc.
+ Copyright (C) 2007-2015 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
@@ -21,7 +21,7 @@
/* Specification. */
#ifdef USE_LONG_DOUBLE
/* Specification found in math.h or isnanl-nolibm.h. */
-extern int rpl_isnanl (long double x);
+extern int rpl_isnanl (long double x) _GL_ATTRIBUTE_CONST;
#elif ! defined USE_FLOAT
/* Specification found in math.h or isnand-nolibm.h. */
extern int rpl_isnand (double x);
@@ -79,11 +79,22 @@ extern int rpl_isnanf (float x);
((sizeof (DOUBLE) + sizeof (unsigned int) - 1) / sizeof (unsigned int))
typedef union { DOUBLE value; unsigned int word[NWORDS]; } memory_double;
+/* Most hosts nowadays use IEEE floating point, so they use IEC 60559
+ representations, have infinities and NaNs, and do not trap on
+ exceptions. Define IEEE_FLOATING_POINT if this host is one of the
+ typical ones. The C11 macro __STDC_IEC_559__ is close to what is
+ wanted here, but is not quite right because this file does not require
+ all the features of C11 Annex F (and does not require C11 at all,
+ for that matter). */
+
+#define IEEE_FLOATING_POINT (FLT_RADIX == 2 && FLT_MANT_DIG == 24 \
+ && FLT_MIN_EXP == -125 && FLT_MAX_EXP == 128)
+
int
FUNC (DOUBLE x)
{
-#ifdef KNOWN_EXPBIT0_LOCATION
-# if defined USE_LONG_DOUBLE && ((defined __ia64 && LDBL_MANT_DIG == 64) || (defined __x86_64__ || defined __amd64__) || (defined __i386 || defined __i386__ || defined _I386 || defined _M_IX86 || defined _X86_))
+#if defined KNOWN_EXPBIT0_LOCATION && IEEE_FLOATING_POINT
+# if defined USE_LONG_DOUBLE && ((defined __ia64 && LDBL_MANT_DIG == 64) || (defined __x86_64__ || defined __amd64__) || (defined __i386 || defined __i386__ || defined _I386 || defined _M_IX86 || defined _X86_)) && !HAVE_SAME_LONG_DOUBLE_AS_DOUBLE
/* Special CPU dependent code is needed to treat bit patterns outside the
IEEE 754 specification (such as Pseudo-NaNs, Pseudo-Infinities,
Pseudo-Zeroes, Unnormalized Numbers, and Pseudo-Denormals) as NaNs.
@@ -117,16 +128,20 @@ FUNC (DOUBLE x)
# else
/* Be careful to not do any floating-point operation on x, such as x == x,
because x may be a signaling NaN. */
-# if defined __SUNPRO_C || defined __DECC || (defined __sgi && !defined __GNUC__)
- /* The Sun C 5.0 compilers and the Compaq (ex-DEC) 6.4 compilers don't
- recognize the initializers as constant expressions. The latter compiler
- also fails when constant-folding 0.0 / 0.0 even when constant-folding is
- not required. The SGI MIPSpro C compiler complains about "floating-point
- operation result is out of range". */
+# if defined __SUNPRO_C || defined __ICC || defined _MSC_VER \
+ || defined __DECC || defined __TINYC__ \
+ || (defined __sgi && !defined __GNUC__)
+ /* The Sun C 5.0, Intel ICC 10.0, Microsoft Visual C/C++ 9.0, Compaq (ex-DEC)
+ 6.4, and TinyCC compilers don't recognize the initializers as constant
+ expressions. The Compaq compiler also fails when constant-folding
+ 0.0 / 0.0 even when constant-folding is not required. The Microsoft
+ Visual C/C++ compiler also fails when constant-folding 1.0 / 0.0 even
+ when constant-folding is not required. The SGI MIPSpro C compiler
+ complains about "floating-point operation result is out of range". */
static DOUBLE zero = L_(0.0);
memory_double nan;
- DOUBLE plus_inf = L_(1.0) / L_(0.0);
- DOUBLE minus_inf = -L_(1.0) / L_(0.0);
+ DOUBLE plus_inf = L_(1.0) / zero;
+ DOUBLE minus_inf = -L_(1.0) / zero;
nan.value = zero / zero;
# else
static memory_double nan = { L_(0.0) / L_(0.0) };
@@ -149,11 +164,12 @@ FUNC (DOUBLE x)
}
# endif
#else
- /* The configuration did not find sufficient information. Give up about
- the signaling NaNs, handle only the quiet NaNs. */
+ /* The configuration did not find sufficient information, or does
+ not use IEEE floating point. Give up about the signaling NaNs;
+ handle only the quiet NaNs. */
if (x == x)
{
-# if defined USE_LONG_DOUBLE && ((defined __ia64 && LDBL_MANT_DIG == 64) || (defined __x86_64__ || defined __amd64__) || (defined __i386 || defined __i386__ || defined _I386 || defined _M_IX86 || defined _X86_))
+# if defined USE_LONG_DOUBLE && ((defined __ia64 && LDBL_MANT_DIG == 64) || (defined __x86_64__ || defined __amd64__) || (defined __i386 || defined __i386__ || defined _I386 || defined _M_IX86 || defined _X86_)) && !HAVE_SAME_LONG_DOUBLE_AS_DOUBLE
/* Detect any special bit patterns that pass ==; see comment above. */
memory_double m1;
memory_double m2;