xref: /netbsd-src/external/lgpl3/gmp/dist/tests/mpz/t-get_d_2exp.c (revision 72c7faa4dbb41dbb0238d6b4a109da0d4b236dd4)
1 /* Test mpz_get_d_2exp.
2 
3 Copyright 2002, 2003, 2012 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 <stdio.h>
21 #include <stdlib.h>
22 #include "gmp-impl.h"
23 #include "tests.h"
24 
25 
26 static void
check_zero(void)27 check_zero (void)
28 {
29   mpz_t   z;
30   double  got, want;
31   long    got_exp, want_exp;
32 
33   mpz_init_set_ui (z, 0);
34 
35   want = 0.0;
36   want_exp = 0;
37   got = mpz_get_d_2exp (&got_exp, z);
38   if (got != want || got_exp != want_exp)
39     {
40       printf    ("mpz_get_d_2exp wrong on zero\n");
41       mpz_trace ("   z    ", z);
42       d_trace   ("   want ", want);
43       d_trace   ("   got  ", got);
44       printf    ("   want exp %ld\n", want_exp);
45       printf    ("   got exp  %ld\n", got_exp);
46       abort();
47     }
48 
49   mpz_clear (z);
50 }
51 
52 static void
check_onebit(void)53 check_onebit (void)
54 {
55   static const unsigned long data[] = {
56     1, 32, 52, 53, 54, 63, 64, 65, 128, 256, 511, 512, 513
57   };
58   mpz_t   z;
59   double  got, want;
60   long    got_exp, want_exp;
61   int     i;
62 
63   mpz_init (z);
64 
65   for (i = 0; i < numberof (data); i++)
66     {
67       mpz_set_ui (z, 1L);
68       mpz_mul_2exp (z, z, data[i]);
69       want = 0.5;
70       want_exp = data[i] + 1;
71       got = mpz_get_d_2exp (&got_exp, z);
72       if (got != want || got_exp != want_exp)
73         {
74           printf    ("mpz_get_d_2exp wrong on 2**%ld\n", data[i]);
75           mpz_trace ("   z    ", z);
76           d_trace   ("   want ", want);
77           d_trace   ("   got  ", got);
78           printf    ("   want exp %ld\n", want_exp);
79           printf    ("   got exp  %ld\n", got_exp);
80           abort();
81         }
82 
83       mpz_set_si (z, -1L);
84       mpz_mul_2exp (z, z, data[i]);
85       want = -0.5;
86       want_exp = data[i] + 1;
87       got = mpz_get_d_2exp (&got_exp, z);
88       if (got != want || got_exp != want_exp)
89         {
90           printf    ("mpz_get_d_2exp wrong on -2**%ld\n", data[i]);
91           mpz_trace ("   z    ", z);
92           d_trace   ("   want ", want);
93           d_trace   ("   got  ", got);
94           printf    ("   want exp %ld\n", want_exp);
95           printf    ("   got exp  %ld\n", got_exp);
96           abort();
97         }
98     }
99   mpz_clear (z);
100 }
101 
102 /* Check that hardware rounding doesn't make mpz_get_d_2exp return a value
103    outside its defined range. */
104 static void
check_round(void)105 check_round (void)
106 {
107   static const unsigned long data[] = { 1, 32, 53, 54, 64, 128, 256, 512 };
108   mpz_t   z;
109   double  got;
110   long    got_exp;
111   int     i, rnd_mode, old_rnd_mode;
112 
113   mpz_init (z);
114   old_rnd_mode = tests_hardware_getround ();
115 
116   for (rnd_mode = 0; rnd_mode < 4; rnd_mode++)
117     {
118       tests_hardware_setround (rnd_mode);
119 
120       for (i = 0; i < numberof (data); i++)
121         {
122           mpz_set_ui (z, 1L);
123           mpz_mul_2exp (z, z, data[i]);
124           mpz_sub_ui (z, z, 1L);
125 
126           got = mpz_get_d_2exp (&got_exp, z);
127           if (got < 0.5 || got >= 1.0)
128             {
129               printf    ("mpz_get_d_2exp wrong on 2**%lu-1\n", data[i]);
130               printf    ("result out of range, expect 0.5 <= got < 1.0\n");
131               printf    ("   rnd_mode = %d\n", rnd_mode);
132               printf    ("   data[i]  = %lu\n", data[i]);
133               mpz_trace ("   z    ", z);
134               d_trace   ("   got  ", got);
135               printf    ("   got exp  %ld\n", got_exp);
136               abort();
137             }
138 
139           mpz_neg (z, z);
140           got = mpz_get_d_2exp (&got_exp, z);
141           if (got <= -1.0 || got > -0.5)
142             {
143               printf    ("mpz_get_d_2exp wrong on -2**%lu-1\n", data[i]);
144               printf    ("result out of range, expect -1.0 < got <= -0.5\n");
145               printf    ("   rnd_mode = %d\n", rnd_mode);
146               printf    ("   data[i]  = %lu\n", data[i]);
147               mpz_trace ("   z    ", z);
148               d_trace   ("   got  ", got);
149               printf    ("   got exp  %ld\n", got_exp);
150               abort();
151             }
152         }
153     }
154 
155   mpz_clear (z);
156   tests_hardware_setround (old_rnd_mode);
157 }
158 
159 static void
check_rand(void)160 check_rand (void)
161 {
162   gmp_randstate_ptr rands = RANDS;
163   int     i;
164   mpz_t   z;
165   double  got;
166   long    got_exp;
167   unsigned long  bits;
168 
169   mpz_init (z);
170 
171   for (i = 0; i < 200; i++)
172     {
173       bits = gmp_urandomm_ui (rands, 512L);
174       mpz_urandomb (z, rands, bits);
175 
176       got = mpz_get_d_2exp (&got_exp, z);
177       if (mpz_sgn (z) == 0)
178         continue;
179       bits = mpz_sizeinbase (z, 2);
180 
181       if (got < 0.5 || got >= 1.0)
182         {
183           printf    ("mpz_get_d_2exp out of range, expect 0.5 <= got < 1.0\n");
184           mpz_trace ("   z    ", z);
185           d_trace   ("   got  ", got);
186           printf    ("   got exp  %ld\n", got_exp);
187           abort();
188         }
189 
190       /* FIXME: If mpz_get_d_2exp rounds upwards we might have got_exp ==
191          bits+1, so leave this test disabled until we decide if that's what
192          should happen, or not.  */
193 #if 0
194       if (got_exp != bits)
195         {
196           printf    ("mpz_get_d_2exp wrong exponent\n", i);
197           mpz_trace ("   z    ", z);
198           d_trace   ("   bits ", bits);
199           d_trace   ("   got  ", got);
200           printf    ("   got exp  %ld\n", got_exp);
201           abort();
202         }
203 #endif
204     }
205   mpz_clear (z);
206 }
207 
208 
209 int
main(void)210 main (void)
211 {
212   tests_start ();
213   mp_trace_base = -16;
214 
215   check_zero ();
216   check_onebit ();
217   check_round ();
218   check_rand ();
219 
220   tests_end ();
221   exit (0);
222 }
223