Coverage Report

Created: 2025-07-01 07:09

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