Branch data Line data Source code
1 : : /* Test of <float.h> substitute.
2 : : Copyright (C) 2011-2012 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 : 99 : pow2f (int n)
34 : : {
35 : 99 : int k = n;
36 : 99 : volatile float x = 1;
37 : 99 : volatile float y = 2;
38 : : /* Invariant: 2^n == x * y^k. */
39 [ + + ]: 99 : if (k < 0)
40 : : {
41 : 49 : y = 0.5f;
42 : 49 : k = - k;
43 : : }
44 [ + + ]: 471 : while (k > 0)
45 : : {
46 [ + + ]: 469 : if (k != 2 * (k / 2))
47 : : {
48 : 266 : x = x * y;
49 : 266 : k = k - 1;
50 : : }
51 [ + + ]: 469 : if (k == 0)
52 : 97 : break;
53 : 372 : y = y * y;
54 : 372 : k = k / 2;
55 : : }
56 : : /* Now k == 0, hence x == 2^n. */
57 : 99 : return x;
58 : : }
59 : :
60 : : /* Return 2^n. */
61 : : static double
62 : 215 : pow2d (int n)
63 : : {
64 : 215 : int k = n;
65 : 215 : volatile double x = 1;
66 : 215 : volatile double y = 2;
67 : : /* Invariant: 2^n == x * y^k. */
68 [ + + ]: 215 : if (k < 0)
69 : : {
70 : 107 : y = 0.5;
71 : 107 : k = - k;
72 : : }
73 [ + + ]: 1256 : while (k > 0)
74 : : {
75 [ + + ]: 1254 : if (k != 2 * (k / 2))
76 : : {
77 : 695 : x = x * y;
78 : 695 : k = k - 1;
79 : : }
80 [ + + ]: 1254 : if (k == 0)
81 : 213 : break;
82 : 1041 : y = y * y;
83 : 1041 : k = k / 2;
84 : : }
85 : : /* Now k == 0, hence x == 2^n. */
86 : 215 : return x;
87 : : }
88 : :
89 : : /* Return 2^n. */
90 : : static long double
91 : 259 : pow2l (int n)
92 : : {
93 : 259 : int k = n;
94 : 259 : volatile long double x = 1;
95 : 259 : volatile long double y = 2;
96 : : /* Invariant: 2^n == x * y^k. */
97 [ + + ]: 259 : if (k < 0)
98 : : {
99 : 129 : y = 0.5L;
100 : 129 : k = - k;
101 : : }
102 [ + + ]: 1570 : while (k > 0)
103 : : {
104 [ + + ]: 1568 : if (k != 2 * (k / 2))
105 : : {
106 : 911 : x = x * y;
107 : 911 : k = k - 1;
108 : : }
109 [ + + ]: 1568 : if (k == 0)
110 : 257 : break;
111 : 1311 : y = y * y;
112 : 1311 : k = k / 2;
113 : : }
114 : : /* Now k == 0, hence x == 2^n. */
115 : 259 : 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 : 1 : 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 : 1 : volatile float m = FLT_MAX;
157 : : int n;
158 : :
159 [ - + ]: 1 : ASSERT (m + m > m);
160 [ + + ]: 50 : for (n = 0; n <= 2 * FLT_MANT_DIG; n++)
161 : : {
162 : 49 : volatile float pow2_n = pow2f (n); /* 2^n */
163 : 49 : volatile float x = m + (m / pow2_n);
164 [ + + ]: 49 : if (x > m)
165 [ - + ]: 25 : ASSERT (x + x == x);
166 : : else
167 [ - + ]: 24 : ASSERT (!(x + x == x));
168 : : }
169 : : }
170 : :
171 : : /* Check the value of FLT_MIN. */
172 : : {
173 : 1 : volatile float m = FLT_MIN;
174 : 1 : volatile float x = pow2f (FLT_MIN_EXP - 1);
175 [ - + ]: 1 : ASSERT (m == x);
176 : : }
177 : :
178 : : /* Check the value of FLT_EPSILON. */
179 : : {
180 : 1 : volatile float e = FLT_EPSILON;
181 : : volatile float me;
182 : : int n;
183 : :
184 : 1 : me = 1.0f + e;
185 [ - + ]: 1 : ASSERT (me > 1.0f);
186 [ - + ]: 1 : ASSERT (me - 1.0f == e);
187 [ + + ]: 50 : for (n = 0; n <= 2 * FLT_MANT_DIG; n++)
188 : : {
189 : 49 : volatile float half_n = pow2f (- n); /* 2^-n */
190 : 49 : volatile float x = me - half_n;
191 [ + + ]: 49 : if (x < me)
192 [ - + ]: 25 : ASSERT (x <= 1.0f);
193 : : }
194 : : }
195 : 1 : }
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 : 1 : 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 : 1 : volatile double m = DBL_MAX;
236 : : int n;
237 : :
238 [ - + ]: 1 : ASSERT (m + m > m);
239 [ + + ]: 108 : for (n = 0; n <= 2 * DBL_MANT_DIG; n++)
240 : : {
241 : 107 : volatile double pow2_n = pow2d (n); /* 2^n */
242 : 107 : volatile double x = m + (m / pow2_n);
243 [ + + ]: 107 : if (x > m)
244 [ - + ]: 54 : ASSERT (x + x == x);
245 : : else
246 [ - + ]: 53 : ASSERT (!(x + x == x));
247 : : }
248 : : }
249 : :
250 : : /* Check the value of DBL_MIN. */
251 : : {
252 : 1 : volatile double m = DBL_MIN;
253 : 1 : volatile double x = pow2d (DBL_MIN_EXP - 1);
254 [ - + ]: 1 : ASSERT (m == x);
255 : : }
256 : :
257 : : /* Check the value of DBL_EPSILON. */
258 : : {
259 : 1 : volatile double e = DBL_EPSILON;
260 : : volatile double me;
261 : : int n;
262 : :
263 : 1 : me = 1.0 + e;
264 [ - + ]: 1 : ASSERT (me > 1.0);
265 [ - + ]: 1 : ASSERT (me - 1.0 == e);
266 [ + + ]: 108 : for (n = 0; n <= 2 * DBL_MANT_DIG; n++)
267 : : {
268 : 107 : volatile double half_n = pow2d (- n); /* 2^-n */
269 : 107 : volatile double x = me - half_n;
270 [ + + ]: 107 : if (x < me)
271 [ - + ]: 54 : ASSERT (x <= 1.0);
272 : : }
273 : : }
274 : 1 : }
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 : 1 : 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 : 1 : volatile long double m = LDBL_MAX;
316 : : int n;
317 : :
318 [ - + ]: 1 : ASSERT (m + m > m);
319 [ + + ]: 130 : for (n = 0; n <= 2 * LDBL_MANT_DIG; n++)
320 : : {
321 : 129 : volatile long double pow2_n = pow2l (n); /* 2^n */
322 : 129 : volatile long double x = m + (m / pow2_n);
323 [ + + ]: 129 : if (x > m)
324 [ - + ]: 65 : ASSERT (x + x == x);
325 : : else
326 [ - + ]: 64 : ASSERT (!(x + x == x));
327 : : }
328 : : }
329 : :
330 : : /* Check the value of LDBL_MIN. */
331 : : {
332 : 1 : volatile long double m = LDBL_MIN;
333 : 1 : volatile long double x = pow2l (LDBL_MIN_EXP - 1);
334 [ - + ]: 1 : ASSERT (m == x);
335 : : }
336 : :
337 : : /* Check the value of LDBL_EPSILON. */
338 : : {
339 : 1 : volatile long double e = LDBL_EPSILON;
340 : : volatile long double me;
341 : : int n;
342 : :
343 : 1 : me = 1.0L + e;
344 [ - + ]: 1 : ASSERT (me > 1.0L);
345 [ - + ]: 1 : ASSERT (me - 1.0L == e);
346 [ + + ]: 130 : for (n = 0; n <= 2 * LDBL_MANT_DIG; n++)
347 : : {
348 : 129 : volatile long double half_n = pow2l (- n); /* 2^-n */
349 : 129 : volatile long double x = me - half_n;
350 [ + + ]: 129 : if (x < me)
351 [ - + ]: 65 : ASSERT (x <= 1.0L);
352 : : }
353 : : }
354 : 1 : }
355 : :
356 : : int
357 : 1 : main ()
358 : : {
359 : 1 : test_float ();
360 : 1 : test_double ();
361 : :
362 : : {
363 : : DECL_LONG_DOUBLE_ROUNDING
364 : :
365 : 1 : BEGIN_LONG_DOUBLE_ROUNDING ();
366 : :
367 : 1 : test_long_double ();
368 : :
369 : 1 : END_LONG_DOUBLE_ROUNDING ();
370 : : }
371 : :
372 : 1 : 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
|