isnan.c   isnan.c 
/* Test for NaN that does not need libm. /* Test for NaN that does not need libm.
Copyright (C) 2007-2010 Free Software Foundation, Inc. Copyright (C) 2007-2014 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or the Free Software Foundation; either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
skipping to change at line 24 skipping to change at line 24
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. * / along with this program. If not, see <http://www.gnu.org/licenses/>. * /
/* Written by Bruno Haible <bruno@clisp.org>, 2007. */ /* Written by Bruno Haible <bruno@clisp.org>, 2007. */
#include <config.h> #include <config.h>
/* Specification. */ /* Specification. */
#ifdef USE_LONG_DOUBLE #ifdef USE_LONG_DOUBLE
/* Specification found in math.h or isnanl-nolibm.h. */ /* 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 #elif ! defined USE_FLOAT
/* Specification found in math.h or isnand-nolibm.h. */ /* Specification found in math.h or isnand-nolibm.h. */
extern int rpl_isnand (double x); extern int rpl_isnand (double x);
#else /* defined USE_FLOAT */ #else /* defined USE_FLOAT */
/* Specification found in math.h or isnanf-nolibm.h. */ /* Specification found in math.h or isnanf-nolibm.h. */
extern int rpl_isnanf (float x); extern int rpl_isnanf (float x);
#endif #endif
#include <float.h> #include <float.h>
#include <string.h> #include <string.h>
skipping to change at line 82 skipping to change at line 82
# define SIZE SIZEOF_FLT # define SIZE SIZEOF_FLT
# define L_(literal) literal##f # define L_(literal) literal##f
#endif #endif
#define EXP_MASK ((MAX_EXP - MIN_EXP) | 7) #define EXP_MASK ((MAX_EXP - MIN_EXP) | 7)
#define NWORDS \ #define NWORDS \
((sizeof (DOUBLE) + sizeof (unsigned int) - 1) / sizeof (unsigned int)) ((sizeof (DOUBLE) + sizeof (unsigned int) - 1) / sizeof (unsigned int))
typedef union { DOUBLE value; unsigned int word[NWORDS]; } memory_double; 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 int
FUNC (DOUBLE x) FUNC (DOUBLE x)
{ {
#ifdef KNOWN_EXPBIT0_LOCATION #if defined KNOWN_EXPBIT0_LOCATION && IEEE_FLOATING_POINT
# if defined USE_LONG_DOUBLE && ((defined __ia64 && LDBL_MANT_DIG == 64) || # if defined USE_LONG_DOUBLE && ((defined __ia64 && LDBL_MANT_DIG == 64) ||
(defined __x86_64__ || defined __amd64__) || (defined __i386 || defined __ (defined __x86_64__ || defined __amd64__) || (defined __i386 || defined __
i386__ || defined _I386 || defined _M_IX86 || defined _X86_)) 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 /* Special CPU dependent code is needed to treat bit patterns outside the
IEEE 754 specification (such as Pseudo-NaNs, Pseudo-Infinities, IEEE 754 specification (such as Pseudo-NaNs, Pseudo-Infinities,
Pseudo-Zeroes, Unnormalized Numbers, and Pseudo-Denormals) as NaNs. Pseudo-Zeroes, Unnormalized Numbers, and Pseudo-Denormals) as NaNs.
These bit patterns are: These bit patterns are:
- exponent = 0x0001..0x7FFF, mantissa bit 63 = 0, - exponent = 0x0001..0x7FFF, mantissa bit 63 = 0,
- exponent = 0x0000, mantissa bit 63 = 1. - exponent = 0x0000, mantissa bit 63 = 1.
The NaN bit pattern is: The NaN bit pattern is:
- exponent = 0x7FFF, mantissa >= 0x8000000000000001. */ - exponent = 0x7FFF, mantissa >= 0x8000000000000001. */
memory_double m; memory_double m;
unsigned int exponent; unsigned int exponent;
skipping to change at line 120 skipping to change at line 131
if (exponent == 0) if (exponent == 0)
return (m.word[1] >> 31); return (m.word[1] >> 31);
else if (exponent == EXP_MASK) else if (exponent == EXP_MASK)
return ((m.word[1] ^ 0x80000000U) | m.word[0]) != 0; return ((m.word[1] ^ 0x80000000U) | m.word[0]) != 0;
else else
return (m.word[1] >> 31) ^ 1; return (m.word[1] >> 31) ^ 1;
# endif # endif
# else # else
/* Be careful to not do any floating-point operation on x, such as x == x , /* Be careful to not do any floating-point operation on x, such as x == x ,
because x may be a signaling NaN. */ because x may be a signaling NaN. */
# if defined __SUNPRO_C || defined __DECC || (defined __sgi && !defined __ # if defined __SUNPRO_C || defined __ICC || defined _MSC_VER \
GNUC__) || defined __DECC || defined __TINYC__ \
/* The Sun C 5.0 compilers and the Compaq (ex-DEC) 6.4 compilers don't || (defined __sgi && !defined __GNUC__)
recognize the initializers as constant expressions. The latter compil /* The Sun C 5.0, Intel ICC 10.0, Microsoft Visual C/C++ 9.0, Compaq (ex-
er DEC)
also fails when constant-folding 0.0 / 0.0 even when constant-folding 6.4, and TinyCC compilers don't recognize the initializers as constant
is expressions. The Compaq compiler also fails when constant-folding
not required. The SGI MIPSpro C compiler complains about "floating-po 0.0 / 0.0 even when constant-folding is not required. The Microsoft
int Visual C/C++ compiler also fails when constant-folding 1.0 / 0.0 even
operation result is out of range". */ 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); static DOUBLE zero = L_(0.0);
memory_double nan; memory_double nan;
DOUBLE plus_inf = L_(1.0) / L_(0.0); DOUBLE plus_inf = L_(1.0) / zero;
DOUBLE minus_inf = -L_(1.0) / L_(0.0); DOUBLE minus_inf = -L_(1.0) / zero;
nan.value = zero / zero; nan.value = zero / zero;
# else # else
static memory_double nan = { L_(0.0) / L_(0.0) }; static memory_double nan = { L_(0.0) / L_(0.0) };
static DOUBLE plus_inf = L_(1.0) / L_(0.0); static DOUBLE plus_inf = L_(1.0) / L_(0.0);
static DOUBLE minus_inf = -L_(1.0) / L_(0.0); static DOUBLE minus_inf = -L_(1.0) / L_(0.0);
# endif # endif
{ {
memory_double m; memory_double m;
/* A NaN can be recognized through its exponent. But exclude +Infinity and /* A NaN can be recognized through its exponent. But exclude +Infinity and
skipping to change at line 152 skipping to change at line 167
if (((m.word[EXPBIT0_WORD] ^ nan.word[EXPBIT0_WORD]) if (((m.word[EXPBIT0_WORD] ^ nan.word[EXPBIT0_WORD])
& (EXP_MASK << EXPBIT0_BIT)) & (EXP_MASK << EXPBIT0_BIT))
== 0) == 0)
return (memcmp (&m.value, &plus_inf, SIZE) != 0 return (memcmp (&m.value, &plus_inf, SIZE) != 0
&& memcmp (&m.value, &minus_inf, SIZE) != 0); && memcmp (&m.value, &minus_inf, SIZE) != 0);
else else
return 0; return 0;
} }
# endif # endif
#else #else
/* The configuration did not find sufficient information. Give up about /* The configuration did not find sufficient information, or does
the signaling NaNs, handle only the quiet NaNs. */ not use IEEE floating point. Give up about the signaling NaNs;
handle only the quiet NaNs. */
if (x == x) 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. */ /* Detect any special bit patterns that pass ==; see comment above. */
memory_double m1; memory_double m1;
memory_double m2; memory_double m2;
memset (&m1.value, 0, SIZE); memset (&m1.value, 0, SIZE);
memset (&m2.value, 0, SIZE); memset (&m2.value, 0, SIZE);
m1.value = x; m1.value = x;
m2.value = x + (x ? 0.0L : -0.0L); m2.value = x + (x ? 0.0L : -0.0L);
if (memcmp (&m1.value, &m2.value, SIZE) != 0) if (memcmp (&m1.value, &m2.value, SIZE) != 0)
return 1; return 1;
 End of changes. 8 change blocks. 
21 lines changed or deleted 35 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/