xref: /netbsd/external/lgpl3/gmp/dist/tests/mpn/t-get_d.c (revision 671ea119)
1 /* Test mpn_get_d.
2 
3 Copyright 2002-2004 Free Software Foundation, Inc.
4 
5 This file is part of the GNU MP Library test suite.
6 
7 The GNU MP Library test suite is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 3 of the License,
10 or (at your option) any later version.
11 
12 The GNU MP Library test suite is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
15 Public License for more details.
16 
17 You should have received a copy of the GNU General Public License along with
18 the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
19 
20 #include "config.h"
21 
22 #include <setjmp.h>
23 #include <signal.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 
27 #include "gmp-impl.h"
28 #include "tests.h"
29 
30 
31 #ifndef _GMP_IEEE_FLOATS
32 #define _GMP_IEEE_FLOATS 0
33 #endif
34 
35 
36 /* Exercise various 2^n values, with various exponents and positive and
37    negative.  */
38 void
check_onebit(void)39 check_onebit (void)
40 {
41   static const int bit_table[] = {
42     0, 1, 2, 3,
43     GMP_NUMB_BITS - 2, GMP_NUMB_BITS - 1,
44     GMP_NUMB_BITS,
45     GMP_NUMB_BITS + 1, GMP_NUMB_BITS + 2,
46     2 * GMP_NUMB_BITS - 2, 2 * GMP_NUMB_BITS - 1,
47     2 * GMP_NUMB_BITS,
48     2 * GMP_NUMB_BITS + 1, 2 * GMP_NUMB_BITS + 2,
49     3 * GMP_NUMB_BITS - 2, 3 * GMP_NUMB_BITS - 1,
50     3 * GMP_NUMB_BITS,
51     3 * GMP_NUMB_BITS + 1, 3 * GMP_NUMB_BITS + 2,
52     4 * GMP_NUMB_BITS - 2, 4 * GMP_NUMB_BITS - 1,
53     4 * GMP_NUMB_BITS,
54     4 * GMP_NUMB_BITS + 1, 4 * GMP_NUMB_BITS + 2,
55     5 * GMP_NUMB_BITS - 2, 5 * GMP_NUMB_BITS - 1,
56     5 * GMP_NUMB_BITS,
57     5 * GMP_NUMB_BITS + 1, 5 * GMP_NUMB_BITS + 2,
58     6 * GMP_NUMB_BITS - 2, 6 * GMP_NUMB_BITS - 1,
59     6 * GMP_NUMB_BITS,
60     6 * GMP_NUMB_BITS + 1, 6 * GMP_NUMB_BITS + 2,
61   };
62   static const int exp_table[] = {
63     0, -100, -10, -1, 1, 10, 100,
64   };
65 
66   /* FIXME: It'd be better to base this on the float format. */
67 #if defined (__vax) || defined (__vax__)
68   int     limit = 127;  /* vax fp numbers have limited range */
69 #else
70   int     limit = 511;
71 #endif
72 
73   int        bit_i, exp_i, i;
74   double     got, want;
75   mp_size_t  nsize, sign;
76   long       bit, exp, want_bit;
77   mp_limb_t  np[20];
78 
79   for (bit_i = 0; bit_i < numberof (bit_table); bit_i++)
80     {
81       bit = bit_table[bit_i];
82 
83       nsize = BITS_TO_LIMBS (bit+1);
84       refmpn_zero (np, nsize);
85       np[bit/GMP_NUMB_BITS] = CNST_LIMB(1) << (bit % GMP_NUMB_BITS);
86 
87       for (exp_i = 0; exp_i < numberof (exp_table); exp_i++)
88         {
89           exp = exp_table[exp_i];
90 
91           want_bit = bit + exp;
92           if (want_bit >= limit || want_bit <= -limit)
93             continue;
94 
95           want = 1.0;
96           for (i = 0; i < want_bit; i++)
97             want *= 2.0;
98           for (i = 0; i > want_bit; i--)
99             want *= 0.5;
100 
101           for (sign = 0; sign >= -1; sign--, want = -want)
102             {
103               got = mpn_get_d (np, nsize, sign, exp);
104               if (got != want)
105                 {
106                   printf    ("mpn_get_d wrong on 2^n\n");
107                   printf    ("   bit      %ld\n", bit);
108                   printf    ("   exp      %ld\n", exp);
109                   printf    ("   want_bit %ld\n", want_bit);
110                   printf    ("   sign     %ld\n", (long) sign);
111                   mpn_trace ("   n        ", np, nsize);
112                   printf    ("   nsize    %ld\n", (long) nsize);
113                   d_trace   ("   want     ", want);
114                   d_trace   ("   got      ", got);
115                   abort();
116                 }
117             }
118         }
119     }
120 }
121 
122 
123 /* Exercise values 2^n+1, while such a value fits the mantissa of a double. */
124 void
check_twobit(void)125 check_twobit (void)
126 {
127   int        i, mant_bits;
128   double     got, want;
129   mp_size_t  nsize, sign;
130   mp_ptr     np;
131 
132   mant_bits = tests_dbl_mant_bits ();
133   if (mant_bits == 0)
134     return;
135 
136   np = refmpn_malloc_limbs (BITS_TO_LIMBS (mant_bits));
137   want = 3.0;
138   for (i = 1; i < mant_bits; i++)
139     {
140       nsize = BITS_TO_LIMBS (i+1);
141       refmpn_zero (np, nsize);
142       np[i/GMP_NUMB_BITS] = CNST_LIMB(1) << (i % GMP_NUMB_BITS);
143       np[0] |= 1;
144 
145       for (sign = 0; sign >= -1; sign--)
146         {
147           got = mpn_get_d (np, nsize, sign, 0);
148           if (got != want)
149             {
150               printf    ("mpn_get_d wrong on 2^%d + 1\n", i);
151               printf    ("   sign     %ld\n", (long) sign);
152               mpn_trace ("   n        ", np, nsize);
153               printf    ("   nsize    %ld\n", (long) nsize);
154               d_trace   ("   want     ", want);
155               d_trace   ("   got      ", got);
156               abort();
157             }
158           want = -want;
159         }
160 
161       want = 2.0 * want - 1.0;
162     }
163 
164   free (np);
165 }
166 
167 
168 /* Expect large negative exponents to underflow to 0.0.
169    Some systems might have hardware traps for such an underflow (though
170    usually it's not the default), so watch out for SIGFPE. */
171 void
check_underflow(void)172 check_underflow (void)
173 {
174   static const long exp_table[] = {
175     -999999L, LONG_MIN,
176   };
177   static const mp_limb_t  np[1] = { 1 };
178 
179   static long exp;
180   mp_size_t  nsize, sign;
181   double     got;
182   int        exp_i;
183 
184   nsize = numberof (np);
185 
186   if (tests_setjmp_sigfpe() == 0)
187     {
188       for (exp_i = 0; exp_i < numberof (exp_table); exp_i++)
189         {
190           exp = exp_table[exp_i];
191 
192           for (sign = 0; sign >= -1; sign--)
193             {
194               got = mpn_get_d (np, nsize, sign, exp);
195               if (got != 0.0)
196                 {
197                   printf  ("mpn_get_d wrong, didn't get 0.0 on underflow\n");
198                   printf  ("  nsize    %ld\n", (long) nsize);
199                   printf  ("  exp      %ld\n", exp);
200                   printf  ("  sign     %ld\n", (long) sign);
201                   d_trace ("  got      ", got);
202                   abort ();
203                 }
204             }
205         }
206     }
207   else
208     {
209       printf ("Warning, underflow to zero tests skipped due to SIGFPE (exp=%ld)\n", exp);
210     }
211   tests_sigfpe_done ();
212 }
213 
214 
215 /* Expect large values to result in +/-inf, on IEEE systems. */
216 void
check_inf(void)217 check_inf (void)
218 {
219   static const long exp_table[] = {
220     999999L, LONG_MAX,
221   };
222   static const mp_limb_t  np[4] = { 1, 1, 1, 1 };
223   long       exp;
224   mp_size_t  nsize, sign, got_sign;
225   double     got;
226   int        exp_i;
227 
228   if (! _GMP_IEEE_FLOATS)
229     return;
230 
231   for (nsize = 1; nsize <= numberof (np); nsize++)
232     {
233       for (exp_i = 0; exp_i < numberof (exp_table); exp_i++)
234         {
235           exp = exp_table[exp_i];
236 
237           for (sign = 0; sign >= -1; sign--)
238             {
239               got = mpn_get_d (np, nsize, sign, exp);
240               got_sign = (got >= 0 ? 0 : -1);
241               if (! tests_isinf (got))
242                 {
243                   printf  ("mpn_get_d wrong, didn't get infinity\n");
244                 bad:
245                   printf  ("  nsize    %ld\n", (long) nsize);
246                   printf  ("  exp      %ld\n", exp);
247                   printf  ("  sign     %ld\n", (long) sign);
248                   d_trace ("  got      ", got);
249                   printf  ("  got sign %ld\n", (long) got_sign);
250                   abort ();
251                 }
252               if (got_sign != sign)
253                 {
254                   printf  ("mpn_get_d wrong sign on infinity\n");
255                   goto bad;
256                 }
257             }
258         }
259     }
260 }
261 
262 /* Check values 2^n approaching and into IEEE denorm range.
263    Some systems might not support denorms, or might have traps setup, so
264    watch out for SIGFPE.  */
265 void
check_ieee_denorm(void)266 check_ieee_denorm (void)
267 {
268   static long exp;
269   mp_limb_t  n = 1;
270   long       i;
271   mp_size_t  sign;
272   double     want, got;
273 
274   if (! _GMP_IEEE_FLOATS)
275     return;
276 
277   if (tests_setjmp_sigfpe() == 0)
278     {
279       exp = -1020;
280       want = 1.0;
281       for (i = 0; i > exp; i--)
282         want *= 0.5;
283 
284       for ( ; exp > -1500 && want != 0.0; exp--)
285         {
286           for (sign = 0; sign >= -1; sign--)
287             {
288               got = mpn_get_d (&n, (mp_size_t) 1, sign, exp);
289               if (got != want)
290                 {
291                   printf  ("mpn_get_d wrong on denorm\n");
292                   printf  ("  n=1\n");
293                   printf  ("  exp   %ld\n", exp);
294                   printf  ("  sign  %ld\n", (long) sign);
295                   d_trace ("  got   ", got);
296                   d_trace ("  want  ", want);
297                   abort ();
298                 }
299               want = -want;
300             }
301           want *= 0.5;
302           FORCE_DOUBLE (want);
303         }
304     }
305   else
306     {
307       printf ("Warning, IEEE denorm tests skipped due to SIGFPE (exp=%ld)\n", exp);
308     }
309   tests_sigfpe_done ();
310 }
311 
312 
313 /* Check values 2^n approaching exponent overflow.
314    Some systems might trap on overflow, so watch out for SIGFPE.  */
315 void
check_ieee_overflow(void)316 check_ieee_overflow (void)
317 {
318   static long exp;
319   mp_limb_t  n = 1;
320   long       i;
321   mp_size_t  sign;
322   double     want, got;
323 
324   if (! _GMP_IEEE_FLOATS)
325     return;
326 
327   if (tests_setjmp_sigfpe() == 0)
328     {
329       exp = 1010;
330       want = 1.0;
331       for (i = 0; i < exp; i++)
332         want *= 2.0;
333 
334       for ( ; exp < 1050; exp++)
335         {
336           for (sign = 0; sign >= -1; sign--)
337             {
338               got = mpn_get_d (&n, (mp_size_t) 1, sign, exp);
339               if (got != want)
340                 {
341                   printf  ("mpn_get_d wrong on overflow\n");
342                   printf  ("  n=1\n");
343                   printf  ("  exp   %ld\n", exp);
344                   printf  ("  sign  %ld\n", (long) sign);
345                   d_trace ("  got   ", got);
346                   d_trace ("  want  ", want);
347                   abort ();
348                 }
349               want = -want;
350             }
351           want *= 2.0;
352           FORCE_DOUBLE (want);
353         }
354     }
355   else
356     {
357       printf ("Warning, IEEE overflow tests skipped due to SIGFPE (exp=%ld)\n", exp);
358     }
359   tests_sigfpe_done ();
360 }
361 
362 
363 /* ARM gcc 2.95.4 was seen generating bad code for ulong->double
364    conversions, resulting in for instance 0x81c25113 incorrectly converted.
365    This test exercises that value, to see mpn_get_d has avoided the
366    problem.  */
367 void
check_0x81c25113(void)368 check_0x81c25113 (void)
369 {
370 #if GMP_NUMB_BITS >= 32
371   double     want = 2176995603.0;
372   double     got;
373   mp_limb_t  np[4];
374   mp_size_t  nsize;
375   long       exp;
376 
377   if (tests_dbl_mant_bits() < 32)
378     return;
379 
380   for (nsize = 1; nsize <= numberof (np); nsize++)
381     {
382       refmpn_zero (np, nsize-1);
383       np[nsize-1] = CNST_LIMB(0x81c25113);
384       exp = - (nsize-1) * GMP_NUMB_BITS;
385       got = mpn_get_d (np, nsize, (mp_size_t) 0, exp);
386       if (got != want)
387         {
388           printf  ("mpn_get_d wrong on 2176995603 (0x81c25113)\n");
389           printf  ("  nsize  %ld\n", (long) nsize);
390           printf  ("  exp    %ld\n", exp);
391           d_trace ("  got    ", got);
392           d_trace ("  want   ", want);
393           abort ();
394         }
395     }
396 #endif
397 }
398 
399 
400 void
check_rand(void)401 check_rand (void)
402 {
403   gmp_randstate_ptr rands = RANDS;
404   int            rep, i;
405   unsigned long  mant_bits;
406   long           exp, exp_min, exp_max;
407   double         got, want, d;
408   mp_size_t      nalloc, nsize, sign;
409   mp_limb_t      nhigh_mask;
410   mp_ptr         np;
411 
412   mant_bits = tests_dbl_mant_bits ();
413   if (mant_bits == 0)
414     return;
415 
416   /* Allow for vax D format with exponent 127 to -128 only.
417      FIXME: Do something to probe for a valid exponent range.  */
418   exp_min = -100 - mant_bits;
419   exp_max =  100 - mant_bits;
420 
421   /* space for mant_bits */
422   nalloc = BITS_TO_LIMBS (mant_bits);
423   np = refmpn_malloc_limbs (nalloc);
424   nhigh_mask = MP_LIMB_T_MAX
425     >> (GMP_NAIL_BITS + nalloc * GMP_NUMB_BITS - mant_bits);
426 
427   for (rep = 0; rep < 200; rep++)
428     {
429       /* random exp_min to exp_max, inclusive */
430       exp = exp_min + (long) gmp_urandomm_ui (rands, exp_max - exp_min + 1);
431 
432       /* mant_bits worth of random at np */
433       if (rep & 1)
434         mpn_random (np, nalloc);
435       else
436         mpn_random2 (np, nalloc);
437       nsize = nalloc;
438       np[nsize-1] &= nhigh_mask;
439       MPN_NORMALIZE (np, nsize);
440       if (nsize == 0)
441         continue;
442 
443       sign = (mp_size_t) gmp_urandomb_ui (rands, 1L) - 1;
444 
445       /* want = {np,nsize}, converting one bit at a time */
446       want = 0.0;
447       for (i = 0, d = 1.0; i < mant_bits; i++, d *= 2.0)
448         if (np[i/GMP_NUMB_BITS] & (CNST_LIMB(1) << (i%GMP_NUMB_BITS)))
449           want += d;
450       if (sign < 0)
451         want = -want;
452 
453       /* want = want * 2^exp */
454       for (i = 0; i < exp; i++)
455         want *= 2.0;
456       for (i = 0; i > exp; i--)
457         want *= 0.5;
458 
459       got = mpn_get_d (np, nsize, sign, exp);
460 
461       if (got != want)
462         {
463           printf    ("mpn_get_d wrong on random data\n");
464           printf    ("   sign     %ld\n", (long) sign);
465           mpn_trace ("   n        ", np, nsize);
466           printf    ("   nsize    %ld\n", (long) nsize);
467           printf    ("   exp      %ld\n", exp);
468           d_trace   ("   want     ", want);
469           d_trace   ("   got      ", got);
470           abort();
471         }
472     }
473 
474   free (np);
475 }
476 
477 
478 int
main(void)479 main (void)
480 {
481   tests_start ();
482   mp_trace_base = -16;
483 
484   check_onebit ();
485   check_twobit ();
486   check_inf ();
487   check_underflow ();
488   check_ieee_denorm ();
489   check_ieee_overflow ();
490   check_0x81c25113 ();
491 #if ! (defined (__vax) || defined (__vax__))
492   check_rand ();
493 #endif
494 
495   tests_end ();
496   exit (0);
497 }
498