isnan.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. /* Test for NaN that does not need libm.
  2. Copyright (C) 2007-2022 Free Software Foundation, Inc.
  3. This file is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Lesser General Public License as
  5. published by the Free Software Foundation; either version 2.1 of the
  6. License, or (at your option) any later version.
  7. This file is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public License
  12. along with this program. If not, see <https://www.gnu.org/licenses/>. */
  13. /* Written by Bruno Haible <bruno@clisp.org>, 2007. */
  14. #include <config.h>
  15. /* Specification. */
  16. #ifdef USE_LONG_DOUBLE
  17. /* Specification found in math.h or isnanl-nolibm.h. */
  18. extern int rpl_isnanl (long double x) _GL_ATTRIBUTE_CONST;
  19. #elif ! defined USE_FLOAT
  20. /* Specification found in math.h or isnand-nolibm.h. */
  21. extern int rpl_isnand (double x);
  22. #else /* defined USE_FLOAT */
  23. /* Specification found in math.h or isnanf-nolibm.h. */
  24. extern int rpl_isnanf (float x);
  25. #endif
  26. #include <float.h>
  27. #include <string.h>
  28. #include "float+.h"
  29. #ifdef USE_LONG_DOUBLE
  30. # define FUNC rpl_isnanl
  31. # define DOUBLE long double
  32. # define MAX_EXP LDBL_MAX_EXP
  33. # define MIN_EXP LDBL_MIN_EXP
  34. # if defined LDBL_EXPBIT0_WORD && defined LDBL_EXPBIT0_BIT
  35. # define KNOWN_EXPBIT0_LOCATION
  36. # define EXPBIT0_WORD LDBL_EXPBIT0_WORD
  37. # define EXPBIT0_BIT LDBL_EXPBIT0_BIT
  38. # endif
  39. # define SIZE SIZEOF_LDBL
  40. # define L_(literal) literal##L
  41. #elif ! defined USE_FLOAT
  42. # define FUNC rpl_isnand
  43. # define DOUBLE double
  44. # define MAX_EXP DBL_MAX_EXP
  45. # define MIN_EXP DBL_MIN_EXP
  46. # if defined DBL_EXPBIT0_WORD && defined DBL_EXPBIT0_BIT
  47. # define KNOWN_EXPBIT0_LOCATION
  48. # define EXPBIT0_WORD DBL_EXPBIT0_WORD
  49. # define EXPBIT0_BIT DBL_EXPBIT0_BIT
  50. # endif
  51. # define SIZE SIZEOF_DBL
  52. # define L_(literal) literal
  53. #else /* defined USE_FLOAT */
  54. # define FUNC rpl_isnanf
  55. # define DOUBLE float
  56. # define MAX_EXP FLT_MAX_EXP
  57. # define MIN_EXP FLT_MIN_EXP
  58. # if defined FLT_EXPBIT0_WORD && defined FLT_EXPBIT0_BIT
  59. # define KNOWN_EXPBIT0_LOCATION
  60. # define EXPBIT0_WORD FLT_EXPBIT0_WORD
  61. # define EXPBIT0_BIT FLT_EXPBIT0_BIT
  62. # endif
  63. # define SIZE SIZEOF_FLT
  64. # define L_(literal) literal##f
  65. #endif
  66. #define EXP_MASK ((MAX_EXP - MIN_EXP) | 7)
  67. #define NWORDS \
  68. ((sizeof (DOUBLE) + sizeof (unsigned int) - 1) / sizeof (unsigned int))
  69. typedef union { DOUBLE value; unsigned int word[NWORDS]; } memory_double;
  70. /* Most hosts nowadays use IEEE floating point, so they use IEC 60559
  71. representations, have infinities and NaNs, and do not trap on
  72. exceptions. Define IEEE_FLOATING_POINT if this host is one of the
  73. typical ones. The C11 macro __STDC_IEC_559__ is close to what is
  74. wanted here, but is not quite right because this file does not require
  75. all the features of C11 Annex F (and does not require C11 at all,
  76. for that matter). */
  77. #define IEEE_FLOATING_POINT (FLT_RADIX == 2 && FLT_MANT_DIG == 24 \
  78. && FLT_MIN_EXP == -125 && FLT_MAX_EXP == 128)
  79. int
  80. FUNC (DOUBLE x)
  81. {
  82. #if defined KNOWN_EXPBIT0_LOCATION && IEEE_FLOATING_POINT
  83. # 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
  84. /* Special CPU dependent code is needed to treat bit patterns outside the
  85. IEEE 754 specification (such as Pseudo-NaNs, Pseudo-Infinities,
  86. Pseudo-Zeroes, Unnormalized Numbers, and Pseudo-Denormals) as NaNs.
  87. These bit patterns are:
  88. - exponent = 0x0001..0x7FFF, mantissa bit 63 = 0,
  89. - exponent = 0x0000, mantissa bit 63 = 1.
  90. The NaN bit pattern is:
  91. - exponent = 0x7FFF, mantissa >= 0x8000000000000001. */
  92. memory_double m;
  93. unsigned int exponent;
  94. m.value = x;
  95. exponent = (m.word[EXPBIT0_WORD] >> EXPBIT0_BIT) & EXP_MASK;
  96. # ifdef WORDS_BIGENDIAN
  97. /* Big endian: EXPBIT0_WORD = 0, EXPBIT0_BIT = 16. */
  98. if (exponent == 0)
  99. return 1 & (m.word[0] >> 15);
  100. else if (exponent == EXP_MASK)
  101. return (((m.word[0] ^ 0x8000U) << 16) | m.word[1] | (m.word[2] >> 16)) != 0;
  102. else
  103. return 1 & ~(m.word[0] >> 15);
  104. # else
  105. /* Little endian: EXPBIT0_WORD = 2, EXPBIT0_BIT = 0. */
  106. if (exponent == 0)
  107. return (m.word[1] >> 31);
  108. else if (exponent == EXP_MASK)
  109. return ((m.word[1] ^ 0x80000000U) | m.word[0]) != 0;
  110. else
  111. return (m.word[1] >> 31) ^ 1;
  112. # endif
  113. # else
  114. /* Be careful to not do any floating-point operation on x, such as x == x,
  115. because x may be a signaling NaN. */
  116. # if defined __SUNPRO_C || defined __ICC || defined _MSC_VER \
  117. || defined __DECC || defined __TINYC__ \
  118. || (defined __sgi && !defined __GNUC__)
  119. /* The Sun C 5.0, Intel ICC 10.0, Microsoft Visual C/C++ 9.0, Compaq (ex-DEC)
  120. 6.4, and TinyCC compilers don't recognize the initializers as constant
  121. expressions. The Compaq compiler also fails when constant-folding
  122. 0.0 / 0.0 even when constant-folding is not required. The Microsoft
  123. Visual C/C++ compiler also fails when constant-folding 1.0 / 0.0 even
  124. when constant-folding is not required. The SGI MIPSpro C compiler
  125. complains about "floating-point operation result is out of range". */
  126. static DOUBLE zero = L_(0.0);
  127. memory_double nan;
  128. DOUBLE plus_inf = L_(1.0) / zero;
  129. DOUBLE minus_inf = -L_(1.0) / zero;
  130. nan.value = zero / zero;
  131. # else
  132. static memory_double nan = { L_(0.0) / L_(0.0) };
  133. static DOUBLE plus_inf = L_(1.0) / L_(0.0);
  134. static DOUBLE minus_inf = -L_(1.0) / L_(0.0);
  135. # endif
  136. {
  137. memory_double m;
  138. /* A NaN can be recognized through its exponent. But exclude +Infinity and
  139. -Infinity, which have the same exponent. */
  140. m.value = x;
  141. if (((m.word[EXPBIT0_WORD] ^ nan.word[EXPBIT0_WORD])
  142. & (EXP_MASK << EXPBIT0_BIT))
  143. == 0)
  144. return (memcmp (&m.value, &plus_inf, SIZE) != 0
  145. && memcmp (&m.value, &minus_inf, SIZE) != 0);
  146. else
  147. return 0;
  148. }
  149. # endif
  150. #else
  151. /* The configuration did not find sufficient information, or does
  152. not use IEEE floating point. Give up about the signaling NaNs;
  153. handle only the quiet NaNs. */
  154. if (x == x)
  155. {
  156. # 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
  157. /* Detect any special bit patterns that pass ==; see comment above. */
  158. memory_double m1;
  159. memory_double m2;
  160. memset (&m1.value, 0, SIZE);
  161. memset (&m2.value, 0, SIZE);
  162. m1.value = x;
  163. m2.value = x + (x ? 0.0L : -0.0L);
  164. if (memcmp (&m1.value, &m2.value, SIZE) != 0)
  165. return 1;
  166. # endif
  167. return 0;
  168. }
  169. else
  170. return 1;
  171. #endif
  172. }