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