2010-09-08 00:34:27 +02:00
/* Test for NaN that does not need libm.
Update Gnulib; add new modules.
This updates Gnulib to v0.0-4889-ge375fe3.
* m4/gnulib-cache.m4: Add `accept', `bind', `close', `connect',
`getpeername', `getsockname', `getsockopt', `listen', `malloc',
`malloca', `recv', `recvfrom', `send', `sendto', `setsockopt',
`shutdown', `socket', and `sockets', requested by
Jan Nieuwenhuizen <janneke-list@xs4all.nl> for cross-MinGW32 builds.
Add `trunc', requested by Mark H Weaver <mhw@netris.org>.
2011-02-14 11:36:25 +01:00
Copyright ( C ) 2007 - 2011 Free Software Foundation , Inc .
2010-09-08 00:34:27 +02:00
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
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU Lesser General Public License for more details .
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/>. */
/* Written by Bruno Haible <bruno@clisp.org>, 2007. */
# include <config.h>
/* Specification. */
# ifdef USE_LONG_DOUBLE
/* Specification found in math.h or isnanl-nolibm.h. */
extern int rpl_isnanl ( long double x ) ;
# elif ! defined USE_FLOAT
/* Specification found in math.h or isnand-nolibm.h. */
extern int rpl_isnand ( double x ) ;
# else /* defined USE_FLOAT */
/* Specification found in math.h or isnanf-nolibm.h. */
extern int rpl_isnanf ( float x ) ;
# endif
# include <float.h>
# include <string.h>
# include "float+.h"
# ifdef USE_LONG_DOUBLE
# define FUNC rpl_isnanl
# define DOUBLE long double
# define MAX_EXP LDBL_MAX_EXP
# define MIN_EXP LDBL_MIN_EXP
# if defined LDBL_EXPBIT0_WORD && defined LDBL_EXPBIT0_BIT
# define KNOWN_EXPBIT0_LOCATION
# define EXPBIT0_WORD LDBL_EXPBIT0_WORD
# define EXPBIT0_BIT LDBL_EXPBIT0_BIT
# endif
# define SIZE SIZEOF_LDBL
# define L_(literal) literal##L
# elif ! defined USE_FLOAT
# define FUNC rpl_isnand
# define DOUBLE double
# define MAX_EXP DBL_MAX_EXP
# define MIN_EXP DBL_MIN_EXP
# if defined DBL_EXPBIT0_WORD && defined DBL_EXPBIT0_BIT
# define KNOWN_EXPBIT0_LOCATION
# define EXPBIT0_WORD DBL_EXPBIT0_WORD
# define EXPBIT0_BIT DBL_EXPBIT0_BIT
# endif
# define SIZE SIZEOF_DBL
# define L_(literal) literal
# else /* defined USE_FLOAT */
# define FUNC rpl_isnanf
# define DOUBLE float
# define MAX_EXP FLT_MAX_EXP
# define MIN_EXP FLT_MIN_EXP
# if defined FLT_EXPBIT0_WORD && defined FLT_EXPBIT0_BIT
# define KNOWN_EXPBIT0_LOCATION
# define EXPBIT0_WORD FLT_EXPBIT0_WORD
# define EXPBIT0_BIT FLT_EXPBIT0_BIT
# endif
# define SIZE SIZEOF_FLT
# define L_(literal) literal##f
# endif
# define EXP_MASK ((MAX_EXP - MIN_EXP) | 7)
# define NWORDS \
( ( sizeof ( DOUBLE ) + sizeof ( unsigned int ) - 1 ) / sizeof ( unsigned int ) )
typedef union { DOUBLE value ; unsigned int word [ NWORDS ] ; } memory_double ;
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_))
/* 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 .
These bit patterns are :
- exponent = 0x0001 . .0 x7FFF , mantissa bit 63 = 0 ,
- exponent = 0x0000 , mantissa bit 63 = 1.
The NaN bit pattern is :
- exponent = 0x7FFF , mantissa > = 0x8000000000000001 . */
memory_double m ;
unsigned int exponent ;
m . value = x ;
exponent = ( m . word [ EXPBIT0_WORD ] > > EXPBIT0_BIT ) & EXP_MASK ;
# ifdef WORDS_BIGENDIAN
/* Big endian: EXPBIT0_WORD = 0, EXPBIT0_BIT = 16. */
if ( exponent = = 0 )
return 1 & ( m . word [ 0 ] > > 15 ) ;
else if ( exponent = = EXP_MASK )
return ( ( ( m . word [ 0 ] ^ 0x8000U ) < < 16 ) | m . word [ 1 ] | ( m . word [ 2 ] > > 16 ) ) ! = 0 ;
else
return 1 & ~ ( m . word [ 0 ] > > 15 ) ;
# else
/* Little endian: EXPBIT0_WORD = 2, EXPBIT0_BIT = 0. */
if ( exponent = = 0 )
return ( m . word [ 1 ] > > 31 ) ;
else if ( exponent = = EXP_MASK )
return ( ( m . word [ 1 ] ^ 0x80000000U ) | m . word [ 0 ] ) ! = 0 ;
else
return ( m . word [ 1 ] > > 31 ) ^ 1 ;
# endif
# else
/* Be careful to not do any floating-point operation on x, such as x == x,
because x may be a signaling NaN . */
2010-12-07 21:43:04 +01:00
# if defined __TINYC__ || defined __SUNPRO_C || defined __DECC \
| | ( defined __sgi & & ! defined __GNUC__ ) | | defined __ICC
/* The Sun C 5.0, Intel ICC 10.0, and Compaq (ex-DEC) 6.4 compilers don't
2010-09-08 00:34:27 +02:00
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 " . */
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 ) ;
nan . value = zero / zero ;
# else
static memory_double nan = { L_ ( 0.0 ) / L_ ( 0.0 ) } ;
static DOUBLE plus_inf = L_ ( 1.0 ) / L_ ( 0.0 ) ;
static DOUBLE minus_inf = - L_ ( 1.0 ) / L_ ( 0.0 ) ;
# endif
{
memory_double m ;
/* A NaN can be recognized through its exponent. But exclude +Infinity and
- Infinity , which have the same exponent . */
m . value = x ;
if ( ( ( m . word [ EXPBIT0_WORD ] ^ nan . word [ EXPBIT0_WORD ] )
& ( EXP_MASK < < EXPBIT0_BIT ) )
= = 0 )
return ( memcmp ( & m . value , & plus_inf , SIZE ) ! = 0
& & memcmp ( & m . value , & minus_inf , SIZE ) ! = 0 ) ;
else
return 0 ;
}
# endif
# else
/* The configuration did not find sufficient information. 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_))
/* Detect any special bit patterns that pass ==; see comment above. */
memory_double m1 ;
memory_double m2 ;
memset ( & m1 . value , 0 , SIZE ) ;
memset ( & m2 . value , 0 , SIZE ) ;
m1 . value = x ;
m2 . value = x + ( x ? 0.0 L : - 0.0 L ) ;
if ( memcmp ( & m1 . value , & m2 . value , SIZE ) ! = 0 )
return 1 ;
# endif
return 0 ;
}
else
return 1 ;
# endif
}