1 /* signbit() macro: Determine the sign bit of a floating-point number.
2 Copyright (C) 2007, 2009-2018 Free Software Foundation, Inc.
3
4 This program is free software: you can redistribute it and/or
5 modify it under the terms of either:
6
7 * the GNU Lesser General Public License as published by the Free
8 Software Foundation; either version 3 of the License, or (at your
9 option) any later version.
10
11 or
12
13 * the GNU General Public License as published by the Free
14 Software Foundation; either version 2 of the License, or (at your
15 option) any later version.
16
17 or both in parallel, as here.
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program. If not, see <https://www.gnu.org/licenses/>. */
25
26 #include <config.h>
27
28 /* Specification. */
29 #include <math.h>
30
31 #include <string.h>
32 #include "isnanl-nolibm.h"
33 #include "float+.h"
34
35 #ifdef gl_signbitl_OPTIMIZED_MACRO
36 # undef gl_signbitl
37 #endif
38
39 int
gl_signbitl(long double arg)40 gl_signbitl (long double arg)
41 {
42 #if defined LDBL_SIGNBIT_WORD && defined LDBL_SIGNBIT_BIT
43 /* The use of a union to extract the bits of the representation of a
44 'long double' is safe in practice, despite of the "aliasing rules" of
45 C99, because the GCC docs say
46 "Even with '-fstrict-aliasing', type-punning is allowed, provided the
47 memory is accessed through the union type."
48 and similarly for other compilers. */
49 # define NWORDS \
50 ((sizeof (long double) + sizeof (unsigned int) - 1) / sizeof (unsigned int))
51 union { long double value; unsigned int word[NWORDS]; } m;
52 m.value = arg;
53 return (m.word[LDBL_SIGNBIT_WORD] >> LDBL_SIGNBIT_BIT) & 1;
54 #elif HAVE_COPYSIGNL_IN_LIBC
55 return copysignl (1.0L, arg) < 0;
56 #else
57 /* This does not do the right thing for NaN, but this is irrelevant for
58 most use cases. */
59 if (isnanl (arg))
60 return 0;
61 if (arg < 0.0L)
62 return 1;
63 else if (arg == 0.0L)
64 {
65 /* Distinguish 0.0L and -0.0L. */
66 static long double plus_zero = 0.0L;
67 long double arg_mem = arg;
68 return (memcmp (&plus_zero, &arg_mem, SIZEOF_LDBL) != 0);
69 }
70 else
71 return 0;
72 #endif
73 }
74