maint: update copyright
[gnulib.git] / tests / test-float.c
1 /* Test of <float.h> substitute.
2    Copyright (C) 2011-2014 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 General Public License as published by
6    the Free Software Foundation; either version 3 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 General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
16
17 /* Written by Bruno Haible <bruno@clisp.org>, 2011.  */
18
19 #include <config.h>
20
21 #include <float.h>
22
23 #include "fpucw.h"
24 #include "macros.h"
25
26 /* Check that FLT_RADIX is a constant expression.  */
27 int a[] = { FLT_RADIX };
28
29 #if FLT_RADIX == 2
30
31 /* Return 2^n.  */
32 static float
33 pow2f (int n)
34 {
35   int k = n;
36   volatile float x = 1;
37   volatile float y = 2;
38   /* Invariant: 2^n == x * y^k.  */
39   if (k < 0)
40     {
41       y = 0.5f;
42       k = - k;
43     }
44   while (k > 0)
45     {
46       if (k != 2 * (k / 2))
47         {
48           x = x * y;
49           k = k - 1;
50         }
51       if (k == 0)
52         break;
53       y = y * y;
54       k = k / 2;
55     }
56   /* Now k == 0, hence x == 2^n.  */
57   return x;
58 }
59
60 /* Return 2^n.  */
61 static double
62 pow2d (int n)
63 {
64   int k = n;
65   volatile double x = 1;
66   volatile double y = 2;
67   /* Invariant: 2^n == x * y^k.  */
68   if (k < 0)
69     {
70       y = 0.5;
71       k = - k;
72     }
73   while (k > 0)
74     {
75       if (k != 2 * (k / 2))
76         {
77           x = x * y;
78           k = k - 1;
79         }
80       if (k == 0)
81         break;
82       y = y * y;
83       k = k / 2;
84     }
85   /* Now k == 0, hence x == 2^n.  */
86   return x;
87 }
88
89 /* Return 2^n.  */
90 static long double
91 pow2l (int n)
92 {
93   int k = n;
94   volatile long double x = 1;
95   volatile long double y = 2;
96   /* Invariant: 2^n == x * y^k.  */
97   if (k < 0)
98     {
99       y = 0.5L;
100       k = - k;
101     }
102   while (k > 0)
103     {
104       if (k != 2 * (k / 2))
105         {
106           x = x * y;
107           k = k - 1;
108         }
109       if (k == 0)
110         break;
111       y = y * y;
112       k = k / 2;
113     }
114   /* Now k == 0, hence x == 2^n.  */
115   return x;
116 }
117
118 /* ----------------------- Check macros for 'float' ----------------------- */
119
120 /* Check that the FLT_* macros expand to constant expressions.  */
121 int fb[] =
122   {
123     FLT_MANT_DIG, FLT_MIN_EXP, FLT_MAX_EXP,
124     FLT_DIG, FLT_MIN_10_EXP, FLT_MAX_10_EXP
125   };
126 float fc[] = { FLT_EPSILON, FLT_MIN, FLT_MAX };
127
128 static void
129 test_float (void)
130 {
131   /* Check that the value of FLT_MIN_EXP is well parenthesized.  */
132   ASSERT ((FLT_MIN_EXP % 101111) == (FLT_MIN_EXP) % 101111);
133
134   /* Check that the value of DBL_MIN_10_EXP is well parenthesized.  */
135   ASSERT ((FLT_MIN_10_EXP % 101111) == (FLT_MIN_10_EXP) % 101111);
136
137   /* Check that 'float' is as specified in IEEE 754.  */
138   ASSERT (FLT_MANT_DIG == 24);
139   ASSERT (FLT_MIN_EXP == -125);
140   ASSERT (FLT_MAX_EXP == 128);
141
142   /* Check the value of FLT_MIN_10_EXP.  */
143   ASSERT (FLT_MIN_10_EXP == - (int) (- (FLT_MIN_EXP - 1) * 0.30103));
144
145   /* Check the value of FLT_DIG.  */
146   ASSERT (FLT_DIG == (int) ((FLT_MANT_DIG - 1) * 0.30103));
147
148   /* Check the value of FLT_MIN_10_EXP.  */
149   ASSERT (FLT_MIN_10_EXP == - (int) (- (FLT_MIN_EXP - 1) * 0.30103));
150
151   /* Check the value of FLT_MAX_10_EXP.  */
152   ASSERT (FLT_MAX_10_EXP == (int) (FLT_MAX_EXP * 0.30103));
153
154   /* Check the value of FLT_MAX.  */
155   {
156     volatile float m = FLT_MAX;
157     int n;
158
159     ASSERT (m + m > m);
160     for (n = 0; n <= 2 * FLT_MANT_DIG; n++)
161       {
162         volatile float pow2_n = pow2f (n); /* 2^n */
163         volatile float x = m + (m / pow2_n);
164         if (x > m)
165           ASSERT (x + x == x);
166         else
167           ASSERT (!(x + x == x));
168       }
169   }
170
171   /* Check the value of FLT_MIN.  */
172   {
173     volatile float m = FLT_MIN;
174     volatile float x = pow2f (FLT_MIN_EXP - 1);
175     ASSERT (m == x);
176   }
177
178   /* Check the value of FLT_EPSILON.  */
179   {
180     volatile float e = FLT_EPSILON;
181     volatile float me;
182     int n;
183
184     me = 1.0f + e;
185     ASSERT (me > 1.0f);
186     ASSERT (me - 1.0f == e);
187     for (n = 0; n <= 2 * FLT_MANT_DIG; n++)
188       {
189         volatile float half_n = pow2f (- n); /* 2^-n */
190         volatile float x = me - half_n;
191         if (x < me)
192           ASSERT (x <= 1.0f);
193       }
194   }
195 }
196
197 /* ----------------------- Check macros for 'double' ----------------------- */
198
199 /* Check that the DBL_* macros expand to constant expressions.  */
200 int db[] =
201   {
202     DBL_MANT_DIG, DBL_MIN_EXP, DBL_MAX_EXP,
203     DBL_DIG, DBL_MIN_10_EXP, DBL_MAX_10_EXP
204   };
205 double dc[] = { DBL_EPSILON, DBL_MIN, DBL_MAX };
206
207 static void
208 test_double (void)
209 {
210   /* Check that the value of DBL_MIN_EXP is well parenthesized.  */
211   ASSERT ((DBL_MIN_EXP % 101111) == (DBL_MIN_EXP) % 101111);
212
213   /* Check that the value of DBL_MIN_10_EXP is well parenthesized.  */
214   ASSERT ((DBL_MIN_10_EXP % 101111) == (DBL_MIN_10_EXP) % 101111);
215
216   /* Check that 'double' is as specified in IEEE 754.  */
217   ASSERT (DBL_MANT_DIG == 53);
218   ASSERT (DBL_MIN_EXP == -1021);
219   ASSERT (DBL_MAX_EXP == 1024);
220
221   /* Check the value of DBL_MIN_10_EXP.  */
222   ASSERT (DBL_MIN_10_EXP == - (int) (- (DBL_MIN_EXP - 1) * 0.30103));
223
224   /* Check the value of DBL_DIG.  */
225   ASSERT (DBL_DIG == (int) ((DBL_MANT_DIG - 1) * 0.30103));
226
227   /* Check the value of DBL_MIN_10_EXP.  */
228   ASSERT (DBL_MIN_10_EXP == - (int) (- (DBL_MIN_EXP - 1) * 0.30103));
229
230   /* Check the value of DBL_MAX_10_EXP.  */
231   ASSERT (DBL_MAX_10_EXP == (int) (DBL_MAX_EXP * 0.30103));
232
233   /* Check the value of DBL_MAX.  */
234   {
235     volatile double m = DBL_MAX;
236     int n;
237
238     ASSERT (m + m > m);
239     for (n = 0; n <= 2 * DBL_MANT_DIG; n++)
240       {
241         volatile double pow2_n = pow2d (n); /* 2^n */
242         volatile double x = m + (m / pow2_n);
243         if (x > m)
244           ASSERT (x + x == x);
245         else
246           ASSERT (!(x + x == x));
247       }
248   }
249
250   /* Check the value of DBL_MIN.  */
251   {
252     volatile double m = DBL_MIN;
253     volatile double x = pow2d (DBL_MIN_EXP - 1);
254     ASSERT (m == x);
255   }
256
257   /* Check the value of DBL_EPSILON.  */
258   {
259     volatile double e = DBL_EPSILON;
260     volatile double me;
261     int n;
262
263     me = 1.0 + e;
264     ASSERT (me > 1.0);
265     ASSERT (me - 1.0 == e);
266     for (n = 0; n <= 2 * DBL_MANT_DIG; n++)
267       {
268         volatile double half_n = pow2d (- n); /* 2^-n */
269         volatile double x = me - half_n;
270         if (x < me)
271           ASSERT (x <= 1.0);
272       }
273   }
274 }
275
276 /* -------------------- Check macros for 'long double' -------------------- */
277
278 /* Check that the LDBL_* macros expand to constant expressions.  */
279 int lb[] =
280   {
281     LDBL_MANT_DIG, LDBL_MIN_EXP, LDBL_MAX_EXP,
282     LDBL_DIG, LDBL_MIN_10_EXP, LDBL_MAX_10_EXP
283   };
284 long double lc1 = LDBL_EPSILON;
285 long double lc2 = LDBL_MIN;
286 #if 0 /* LDBL_MAX is not a constant expression on some platforms.  */
287 long double lc3 = LDBL_MAX;
288 #endif
289
290 static void
291 test_long_double (void)
292 {
293   /* Check that the value of LDBL_MIN_EXP is well parenthesized.  */
294   ASSERT ((LDBL_MIN_EXP % 101111) == (LDBL_MIN_EXP) % 101111);
295
296   /* Check that the value of LDBL_MIN_10_EXP is well parenthesized.  */
297   ASSERT ((LDBL_MIN_10_EXP % 101111) == (LDBL_MIN_10_EXP) % 101111);
298
299   /* Check that 'long double' is at least as wide as 'double'.  */
300   ASSERT (LDBL_MANT_DIG >= DBL_MANT_DIG);
301   ASSERT (LDBL_MIN_EXP - LDBL_MANT_DIG <= DBL_MIN_EXP - DBL_MANT_DIG);
302   ASSERT (LDBL_MAX_EXP >= DBL_MAX_EXP);
303
304   /* Check the value of LDBL_DIG.  */
305   ASSERT (LDBL_DIG == (int)((LDBL_MANT_DIG - 1) * 0.30103));
306
307   /* Check the value of LDBL_MIN_10_EXP.  */
308   ASSERT (LDBL_MIN_10_EXP == - (int) (- (LDBL_MIN_EXP - 1) * 0.30103));
309
310   /* Check the value of LDBL_MAX_10_EXP.  */
311   ASSERT (LDBL_MAX_10_EXP == (int) (LDBL_MAX_EXP * 0.30103));
312
313   /* Check the value of LDBL_MAX.  */
314   {
315     volatile long double m = LDBL_MAX;
316     int n;
317
318     ASSERT (m + m > m);
319     for (n = 0; n <= 2 * LDBL_MANT_DIG; n++)
320       {
321         volatile long double pow2_n = pow2l (n); /* 2^n */
322         volatile long double x = m + (m / pow2_n);
323         if (x > m)
324           ASSERT (x + x == x);
325         else
326           ASSERT (!(x + x == x));
327       }
328   }
329
330   /* Check the value of LDBL_MIN.  */
331   {
332     volatile long double m = LDBL_MIN;
333     volatile long double x = pow2l (LDBL_MIN_EXP - 1);
334     ASSERT (m == x);
335   }
336
337   /* Check the value of LDBL_EPSILON.  */
338   {
339     volatile long double e = LDBL_EPSILON;
340     volatile long double me;
341     int n;
342
343     me = 1.0L + e;
344     ASSERT (me > 1.0L);
345     ASSERT (me - 1.0L == e);
346     for (n = 0; n <= 2 * LDBL_MANT_DIG; n++)
347       {
348         volatile long double half_n = pow2l (- n); /* 2^-n */
349         volatile long double x = me - half_n;
350         if (x < me)
351           ASSERT (x <= 1.0L);
352       }
353   }
354 }
355
356 int
357 main ()
358 {
359   test_float ();
360   test_double ();
361
362   {
363     DECL_LONG_DOUBLE_ROUNDING
364
365     BEGIN_LONG_DOUBLE_ROUNDING ();
366
367     test_long_double ();
368
369     END_LONG_DOUBLE_ROUNDING ();
370   }
371
372   return 0;
373 }
374
375 #else
376
377 int
378 main ()
379 {
380   fprintf (stderr, "Skipping test: FLT_RADIX is not 2.\n");
381   return 77;
382 }
383
384 #endif