105436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Test for NaN that does not need libm. 205436638acc7c010349a69c3395f1a57c642dc62Ying Wang Copyright (C) 2007-2012 Free Software Foundation, Inc. 305436638acc7c010349a69c3395f1a57c642dc62Ying Wang 405436638acc7c010349a69c3395f1a57c642dc62Ying Wang This program is free software: you can redistribute it and/or modify 505436638acc7c010349a69c3395f1a57c642dc62Ying Wang it under the terms of the GNU General Public License as published by 605436638acc7c010349a69c3395f1a57c642dc62Ying Wang the Free Software Foundation; either version 3 of the License, or 705436638acc7c010349a69c3395f1a57c642dc62Ying Wang (at your option) any later version. 805436638acc7c010349a69c3395f1a57c642dc62Ying Wang 905436638acc7c010349a69c3395f1a57c642dc62Ying Wang This program is distributed in the hope that it will be useful, 1005436638acc7c010349a69c3395f1a57c642dc62Ying Wang but WITHOUT ANY WARRANTY; without even the implied warranty of 1105436638acc7c010349a69c3395f1a57c642dc62Ying Wang MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1205436638acc7c010349a69c3395f1a57c642dc62Ying Wang GNU General Public License for more details. 1305436638acc7c010349a69c3395f1a57c642dc62Ying Wang 1405436638acc7c010349a69c3395f1a57c642dc62Ying Wang You should have received a copy of the GNU General Public License 1505436638acc7c010349a69c3395f1a57c642dc62Ying Wang along with this program. If not, see <http://www.gnu.org/licenses/>. */ 1605436638acc7c010349a69c3395f1a57c642dc62Ying Wang 1705436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Written by Bruno Haible <bruno@clisp.org>, 2007. */ 1805436638acc7c010349a69c3395f1a57c642dc62Ying Wang 1905436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <config.h> 2005436638acc7c010349a69c3395f1a57c642dc62Ying Wang 2105436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Specification. */ 2205436638acc7c010349a69c3395f1a57c642dc62Ying Wang#ifdef USE_LONG_DOUBLE 2305436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Specification found in math.h or isnanl-nolibm.h. */ 2405436638acc7c010349a69c3395f1a57c642dc62Ying Wangextern int rpl_isnanl (long double x) _GL_ATTRIBUTE_CONST; 2505436638acc7c010349a69c3395f1a57c642dc62Ying Wang#elif ! defined USE_FLOAT 2605436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Specification found in math.h or isnand-nolibm.h. */ 2705436638acc7c010349a69c3395f1a57c642dc62Ying Wangextern int rpl_isnand (double x); 2805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#else /* defined USE_FLOAT */ 2905436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Specification found in math.h or isnanf-nolibm.h. */ 3005436638acc7c010349a69c3395f1a57c642dc62Ying Wangextern int rpl_isnanf (float x); 3105436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif 3205436638acc7c010349a69c3395f1a57c642dc62Ying Wang 3305436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <float.h> 3405436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <string.h> 3505436638acc7c010349a69c3395f1a57c642dc62Ying Wang 3605436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include "float+.h" 3705436638acc7c010349a69c3395f1a57c642dc62Ying Wang 3805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#ifdef USE_LONG_DOUBLE 3905436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define FUNC rpl_isnanl 4005436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define DOUBLE long double 4105436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define MAX_EXP LDBL_MAX_EXP 4205436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define MIN_EXP LDBL_MIN_EXP 4305436638acc7c010349a69c3395f1a57c642dc62Ying Wang# if defined LDBL_EXPBIT0_WORD && defined LDBL_EXPBIT0_BIT 4405436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define KNOWN_EXPBIT0_LOCATION 4505436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define EXPBIT0_WORD LDBL_EXPBIT0_WORD 4605436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define EXPBIT0_BIT LDBL_EXPBIT0_BIT 4705436638acc7c010349a69c3395f1a57c642dc62Ying Wang# endif 4805436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define SIZE SIZEOF_LDBL 4905436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define L_(literal) literal##L 5005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#elif ! defined USE_FLOAT 5105436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define FUNC rpl_isnand 5205436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define DOUBLE double 5305436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define MAX_EXP DBL_MAX_EXP 5405436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define MIN_EXP DBL_MIN_EXP 5505436638acc7c010349a69c3395f1a57c642dc62Ying Wang# if defined DBL_EXPBIT0_WORD && defined DBL_EXPBIT0_BIT 5605436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define KNOWN_EXPBIT0_LOCATION 5705436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define EXPBIT0_WORD DBL_EXPBIT0_WORD 5805436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define EXPBIT0_BIT DBL_EXPBIT0_BIT 5905436638acc7c010349a69c3395f1a57c642dc62Ying Wang# endif 6005436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define SIZE SIZEOF_DBL 6105436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define L_(literal) literal 6205436638acc7c010349a69c3395f1a57c642dc62Ying Wang#else /* defined USE_FLOAT */ 6305436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define FUNC rpl_isnanf 6405436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define DOUBLE float 6505436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define MAX_EXP FLT_MAX_EXP 6605436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define MIN_EXP FLT_MIN_EXP 6705436638acc7c010349a69c3395f1a57c642dc62Ying Wang# if defined FLT_EXPBIT0_WORD && defined FLT_EXPBIT0_BIT 6805436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define KNOWN_EXPBIT0_LOCATION 6905436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define EXPBIT0_WORD FLT_EXPBIT0_WORD 7005436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define EXPBIT0_BIT FLT_EXPBIT0_BIT 7105436638acc7c010349a69c3395f1a57c642dc62Ying Wang# endif 7205436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define SIZE SIZEOF_FLT 7305436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define L_(literal) literal##f 7405436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif 7505436638acc7c010349a69c3395f1a57c642dc62Ying Wang 7605436638acc7c010349a69c3395f1a57c642dc62Ying Wang#define EXP_MASK ((MAX_EXP - MIN_EXP) | 7) 7705436638acc7c010349a69c3395f1a57c642dc62Ying Wang 7805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#define NWORDS \ 7905436638acc7c010349a69c3395f1a57c642dc62Ying Wang ((sizeof (DOUBLE) + sizeof (unsigned int) - 1) / sizeof (unsigned int)) 8005436638acc7c010349a69c3395f1a57c642dc62Ying Wangtypedef union { DOUBLE value; unsigned int word[NWORDS]; } memory_double; 8105436638acc7c010349a69c3395f1a57c642dc62Ying Wang 8205436638acc7c010349a69c3395f1a57c642dc62Ying Wangint 8305436638acc7c010349a69c3395f1a57c642dc62Ying WangFUNC (DOUBLE x) 8405436638acc7c010349a69c3395f1a57c642dc62Ying Wang{ 8505436638acc7c010349a69c3395f1a57c642dc62Ying Wang#ifdef KNOWN_EXPBIT0_LOCATION 8605436638acc7c010349a69c3395f1a57c642dc62Ying Wang# 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 8705436638acc7c010349a69c3395f1a57c642dc62Ying Wang /* Special CPU dependent code is needed to treat bit patterns outside the 8805436638acc7c010349a69c3395f1a57c642dc62Ying Wang IEEE 754 specification (such as Pseudo-NaNs, Pseudo-Infinities, 8905436638acc7c010349a69c3395f1a57c642dc62Ying Wang Pseudo-Zeroes, Unnormalized Numbers, and Pseudo-Denormals) as NaNs. 9005436638acc7c010349a69c3395f1a57c642dc62Ying Wang These bit patterns are: 9105436638acc7c010349a69c3395f1a57c642dc62Ying Wang - exponent = 0x0001..0x7FFF, mantissa bit 63 = 0, 9205436638acc7c010349a69c3395f1a57c642dc62Ying Wang - exponent = 0x0000, mantissa bit 63 = 1. 9305436638acc7c010349a69c3395f1a57c642dc62Ying Wang The NaN bit pattern is: 9405436638acc7c010349a69c3395f1a57c642dc62Ying Wang - exponent = 0x7FFF, mantissa >= 0x8000000000000001. */ 9505436638acc7c010349a69c3395f1a57c642dc62Ying Wang memory_double m; 9605436638acc7c010349a69c3395f1a57c642dc62Ying Wang unsigned int exponent; 9705436638acc7c010349a69c3395f1a57c642dc62Ying Wang 9805436638acc7c010349a69c3395f1a57c642dc62Ying Wang m.value = x; 9905436638acc7c010349a69c3395f1a57c642dc62Ying Wang exponent = (m.word[EXPBIT0_WORD] >> EXPBIT0_BIT) & EXP_MASK; 10005436638acc7c010349a69c3395f1a57c642dc62Ying Wang# ifdef WORDS_BIGENDIAN 10105436638acc7c010349a69c3395f1a57c642dc62Ying Wang /* Big endian: EXPBIT0_WORD = 0, EXPBIT0_BIT = 16. */ 10205436638acc7c010349a69c3395f1a57c642dc62Ying Wang if (exponent == 0) 10305436638acc7c010349a69c3395f1a57c642dc62Ying Wang return 1 & (m.word[0] >> 15); 10405436638acc7c010349a69c3395f1a57c642dc62Ying Wang else if (exponent == EXP_MASK) 10505436638acc7c010349a69c3395f1a57c642dc62Ying Wang return (((m.word[0] ^ 0x8000U) << 16) | m.word[1] | (m.word[2] >> 16)) != 0; 10605436638acc7c010349a69c3395f1a57c642dc62Ying Wang else 10705436638acc7c010349a69c3395f1a57c642dc62Ying Wang return 1 & ~(m.word[0] >> 15); 10805436638acc7c010349a69c3395f1a57c642dc62Ying Wang# else 10905436638acc7c010349a69c3395f1a57c642dc62Ying Wang /* Little endian: EXPBIT0_WORD = 2, EXPBIT0_BIT = 0. */ 11005436638acc7c010349a69c3395f1a57c642dc62Ying Wang if (exponent == 0) 11105436638acc7c010349a69c3395f1a57c642dc62Ying Wang return (m.word[1] >> 31); 11205436638acc7c010349a69c3395f1a57c642dc62Ying Wang else if (exponent == EXP_MASK) 11305436638acc7c010349a69c3395f1a57c642dc62Ying Wang return ((m.word[1] ^ 0x80000000U) | m.word[0]) != 0; 11405436638acc7c010349a69c3395f1a57c642dc62Ying Wang else 11505436638acc7c010349a69c3395f1a57c642dc62Ying Wang return (m.word[1] >> 31) ^ 1; 11605436638acc7c010349a69c3395f1a57c642dc62Ying Wang# endif 11705436638acc7c010349a69c3395f1a57c642dc62Ying Wang# else 11805436638acc7c010349a69c3395f1a57c642dc62Ying Wang /* Be careful to not do any floating-point operation on x, such as x == x, 11905436638acc7c010349a69c3395f1a57c642dc62Ying Wang because x may be a signaling NaN. */ 12005436638acc7c010349a69c3395f1a57c642dc62Ying Wang# if defined __SUNPRO_C || defined __ICC || defined _MSC_VER \ 12105436638acc7c010349a69c3395f1a57c642dc62Ying Wang || defined __DECC || defined __TINYC__ \ 12205436638acc7c010349a69c3395f1a57c642dc62Ying Wang || (defined __sgi && !defined __GNUC__) 12305436638acc7c010349a69c3395f1a57c642dc62Ying Wang /* The Sun C 5.0, Intel ICC 10.0, Microsoft Visual C/C++ 9.0, Compaq (ex-DEC) 12405436638acc7c010349a69c3395f1a57c642dc62Ying Wang 6.4, and TinyCC compilers don't recognize the initializers as constant 12505436638acc7c010349a69c3395f1a57c642dc62Ying Wang expressions. The Compaq compiler also fails when constant-folding 12605436638acc7c010349a69c3395f1a57c642dc62Ying Wang 0.0 / 0.0 even when constant-folding is not required. The Microsoft 12705436638acc7c010349a69c3395f1a57c642dc62Ying Wang Visual C/C++ compiler also fails when constant-folding 1.0 / 0.0 even 12805436638acc7c010349a69c3395f1a57c642dc62Ying Wang when constant-folding is not required. The SGI MIPSpro C compiler 12905436638acc7c010349a69c3395f1a57c642dc62Ying Wang complains about "floating-point operation result is out of range". */ 13005436638acc7c010349a69c3395f1a57c642dc62Ying Wang static DOUBLE zero = L_(0.0); 13105436638acc7c010349a69c3395f1a57c642dc62Ying Wang memory_double nan; 13205436638acc7c010349a69c3395f1a57c642dc62Ying Wang DOUBLE plus_inf = L_(1.0) / zero; 13305436638acc7c010349a69c3395f1a57c642dc62Ying Wang DOUBLE minus_inf = -L_(1.0) / zero; 13405436638acc7c010349a69c3395f1a57c642dc62Ying Wang nan.value = zero / zero; 13505436638acc7c010349a69c3395f1a57c642dc62Ying Wang# else 13605436638acc7c010349a69c3395f1a57c642dc62Ying Wang static memory_double nan = { L_(0.0) / L_(0.0) }; 13705436638acc7c010349a69c3395f1a57c642dc62Ying Wang static DOUBLE plus_inf = L_(1.0) / L_(0.0); 13805436638acc7c010349a69c3395f1a57c642dc62Ying Wang static DOUBLE minus_inf = -L_(1.0) / L_(0.0); 13905436638acc7c010349a69c3395f1a57c642dc62Ying Wang# endif 14005436638acc7c010349a69c3395f1a57c642dc62Ying Wang { 14105436638acc7c010349a69c3395f1a57c642dc62Ying Wang memory_double m; 14205436638acc7c010349a69c3395f1a57c642dc62Ying Wang 14305436638acc7c010349a69c3395f1a57c642dc62Ying Wang /* A NaN can be recognized through its exponent. But exclude +Infinity and 14405436638acc7c010349a69c3395f1a57c642dc62Ying Wang -Infinity, which have the same exponent. */ 14505436638acc7c010349a69c3395f1a57c642dc62Ying Wang m.value = x; 14605436638acc7c010349a69c3395f1a57c642dc62Ying Wang if (((m.word[EXPBIT0_WORD] ^ nan.word[EXPBIT0_WORD]) 14705436638acc7c010349a69c3395f1a57c642dc62Ying Wang & (EXP_MASK << EXPBIT0_BIT)) 14805436638acc7c010349a69c3395f1a57c642dc62Ying Wang == 0) 14905436638acc7c010349a69c3395f1a57c642dc62Ying Wang return (memcmp (&m.value, &plus_inf, SIZE) != 0 15005436638acc7c010349a69c3395f1a57c642dc62Ying Wang && memcmp (&m.value, &minus_inf, SIZE) != 0); 15105436638acc7c010349a69c3395f1a57c642dc62Ying Wang else 15205436638acc7c010349a69c3395f1a57c642dc62Ying Wang return 0; 15305436638acc7c010349a69c3395f1a57c642dc62Ying Wang } 15405436638acc7c010349a69c3395f1a57c642dc62Ying Wang# endif 15505436638acc7c010349a69c3395f1a57c642dc62Ying Wang#else 15605436638acc7c010349a69c3395f1a57c642dc62Ying Wang /* The configuration did not find sufficient information. Give up about 15705436638acc7c010349a69c3395f1a57c642dc62Ying Wang the signaling NaNs, handle only the quiet NaNs. */ 15805436638acc7c010349a69c3395f1a57c642dc62Ying Wang if (x == x) 15905436638acc7c010349a69c3395f1a57c642dc62Ying Wang { 16005436638acc7c010349a69c3395f1a57c642dc62Ying Wang# 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 16105436638acc7c010349a69c3395f1a57c642dc62Ying Wang /* Detect any special bit patterns that pass ==; see comment above. */ 16205436638acc7c010349a69c3395f1a57c642dc62Ying Wang memory_double m1; 16305436638acc7c010349a69c3395f1a57c642dc62Ying Wang memory_double m2; 16405436638acc7c010349a69c3395f1a57c642dc62Ying Wang 16505436638acc7c010349a69c3395f1a57c642dc62Ying Wang memset (&m1.value, 0, SIZE); 16605436638acc7c010349a69c3395f1a57c642dc62Ying Wang memset (&m2.value, 0, SIZE); 16705436638acc7c010349a69c3395f1a57c642dc62Ying Wang m1.value = x; 16805436638acc7c010349a69c3395f1a57c642dc62Ying Wang m2.value = x + (x ? 0.0L : -0.0L); 16905436638acc7c010349a69c3395f1a57c642dc62Ying Wang if (memcmp (&m1.value, &m2.value, SIZE) != 0) 17005436638acc7c010349a69c3395f1a57c642dc62Ying Wang return 1; 17105436638acc7c010349a69c3395f1a57c642dc62Ying Wang# endif 17205436638acc7c010349a69c3395f1a57c642dc62Ying Wang return 0; 17305436638acc7c010349a69c3395f1a57c642dc62Ying Wang } 17405436638acc7c010349a69c3395f1a57c642dc62Ying Wang else 17505436638acc7c010349a69c3395f1a57c642dc62Ying Wang return 1; 17605436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif 17705436638acc7c010349a69c3395f1a57c642dc62Ying Wang} 178