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