New module 'signbit'.
[gnulib.git] / m4 / signbit.m4
1 # signbit.m4 serial 1
2 dnl Copyright (C) 2007 Free Software Foundation, Inc.
3 dnl This file is free software; the Free Software Foundation
4 dnl gives unlimited permission to copy and/or distribute it,
5 dnl with or without modifications, as long as this notice is preserved.
6
7 AC_DEFUN([gl_SIGNBIT],
8 [
9   AC_REQUIRE([gl_MATH_H_DEFAULTS])
10   AC_CACHE_CHECK([for signbit macro], [gl_cv_func_signbit],
11     [
12       AC_TRY_RUN([
13 #include <math.h>
14 #include <string.h>
15 float p0f = 0.0f;
16 float m0f = -0.0f;
17 double p0d = 0.0;
18 double m0d = -0.0;
19 long double p0l = 0.0L;
20 long double m0l = -0.0L;
21 int main ()
22 {
23   {
24     float plus_inf = 1.0f / p0f;
25     float minus_inf = -1.0f / p0f;
26     if (!(!signbit (255.0f)
27           && signbit (-255.0f)
28           && !signbit (p0f)
29           && (memcmp (&m0f, &p0f, sizeof (float)) == 0 || signbit (m0f))
30           && !signbit (plus_inf)
31           && signbit (minus_inf)))
32       return 1;
33   }
34   {
35     double plus_inf = 1.0 / p0d;
36     double minus_inf = -1.0 / p0d;
37     if (!(!signbit (255.0)
38           && signbit (-255.0)
39           && !signbit (p0d)
40           && (memcmp (&m0d, &p0d, sizeof (double)) == 0 || signbit (m0d))
41           && !signbit (plus_inf)
42           && signbit (minus_inf)))
43       return 1;
44   }
45   {
46     long double plus_inf = 1.0L / p0l;
47     long double minus_inf = -1.0L / p0l;
48     if (!(!signbit (255.0L)
49           && signbit (-255.0L)
50           && !signbit (p0l)
51           && (memcmp (&m0l, &p0l, sizeof (long double)) == 0 || signbit (m0l))
52           && !signbit (plus_inf)
53           && signbit (minus_inf)))
54       return 1;
55   }
56   return 0;
57 }], [gl_cv_func_signbit=yes], [gl_cv_func_signbit=no],
58         [gl_cv_func_signbit="guessing no"])
59     ])
60   if test "$gl_cv_func_signbit" != yes; then
61     REPLACE_SIGNBIT=1
62     AC_LIBOBJ([signbitf])
63     AC_LIBOBJ([signbitd])
64     AC_LIBOBJ([signbitl])
65     gl_FLOAT_SIGN_LOCATION
66     gl_DOUBLE_SIGN_LOCATION
67     gl_LONG_DOUBLE_SIGN_LOCATION
68   fi
69 ])
70
71 AC_DEFUN([gl_FLOAT_SIGN_LOCATION],
72 [
73   gl_FLOATTYPE_SIGN_LOCATION([float], [gl_cv_cc_float_signbit], [f], [FLT])
74 ])
75
76 AC_DEFUN([gl_DOUBLE_SIGN_LOCATION],
77 [
78   gl_FLOATTYPE_SIGN_LOCATION([double], [gl_cv_cc_double_signbit], [], [DBL])
79 ])
80
81 AC_DEFUN([gl_LONG_DOUBLE_SIGN_LOCATION],
82 [
83   gl_FLOATTYPE_SIGN_LOCATION([long double], [gl_cv_cc_long_double_signbit], [L], [LDBL])
84 ])
85
86 AC_DEFUN([gl_FLOATTYPE_SIGN_LOCATION],
87 [
88   AC_CACHE_CHECK([where to find the sign bit in a '$1'],
89     [$2],
90     [
91       AC_TRY_RUN([
92 #include <stddef.h>
93 #include <stdio.h>
94 #define NWORDS \
95   ((sizeof ($1) + sizeof (unsigned int) - 1) / sizeof (unsigned int))
96 typedef union { $1 value; unsigned int word[NWORDS]; }
97         memory_float;
98 static memory_float plus = { 1.0$3 };
99 static memory_float minus = { -1.0$3 };
100 int main ()
101 {
102   size_t j, k, i;
103   unsigned int m;
104   FILE *fp = fopen ("conftest.out", "w");
105   if (fp == NULL)
106     return 1;
107   /* Find the different bit.  */
108   k = 0; m = 0;
109   for (j = 0; j < NWORDS; j++)
110     {
111       unsigned int x = plus.word[j] ^ minus.word[j];
112       if ((x & (x - 1)) || (x && m))
113         {
114           /* More than one bit difference.  */
115           fprintf (fp, "unknown");
116           return 1;
117         }
118       if (x)
119         {
120           k = j;
121           m = x;
122         }
123     }
124   if (m == 0)
125     {
126       /* No difference.  */
127       fprintf (fp, "unknown");
128       return 1;
129     }
130   /* Now m = plus.word[k] ^ ~minus.word[k].  */
131   if (plus.word[k] & ~minus.word[k])
132     {
133       /* Oh? The sign bit is set in the positive and cleared in the negative
134          numbers?  */
135       fprintf (fp, "unknown");
136       return 1;
137     }
138   for (i = 0; ; i++)
139     if ((m >> i) & 1)
140       break;
141   fprintf (fp, "word %d bit %d", (int) k, (int) i);
142   return (fclose (fp) != 0);
143 }
144         ],
145         [$2=`cat conftest.out`],
146         [$2="unknown"],
147         [
148           dnl When cross-compiling, we don't know. It depends on the
149           dnl ABI and compiler version. There are too many cases.
150           $2="unknown"
151         ])
152       rm -f conftest.out
153     ])
154   case "$]$2[" in
155     word*bit*)
156       word=`echo "$]$2[" | sed -e 's/word //' -e 's/ bit.*//'`
157       bit=`echo "$]$2[" | sed -e 's/word.*bit //'`
158       AC_DEFINE_UNQUOTED([$4][_SIGNBIT_WORD], [$word],
159         [Define as the word index where to find the sign of '$1'.])
160       AC_DEFINE_UNQUOTED([$4][_SIGNBIT_BIT], [$bit],
161         [Define as the bit index in the word where to find the sign of '$1'.])
162       ;;
163   esac
164 ])