1 /* Test mpz_cmp_d and mpz_cmpabs_d.
2
3 Copyright 2001-2003, 2005, 2013 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 <math.h>
21
22 #include "testutils.h"
23
24 /* FIXME: Not sure if the tests here are exhaustive. Ought to try to get
25 each possible exit from mpz_cmp_d (and mpz_cmpabs_d) exercised. */
26
27
28 #define SGN(n) ((n) > 0 ? 1 : (n) < 0 ? -1 : 0)
29
30
31 void
32 check_one (const char *name, mpz_srcptr x, double y, int cmp, int cmpabs)
33 {
34 int got;
35
36 got = mpz_cmp_d (x, y);
37 if (SGN(got) != cmp)
38 {
39 unsigned i;
40 printf ("mpz_cmp_d wrong (from %s)\n", name);
41 printf (" got %d\n", got);
42 printf (" want %d\n", cmp);
43 fail:
44 printf (" x=");
45 mpz_out_str (stdout, 10, x);
46 printf ("\n y %g\n", y);
47 printf (" x=0x");
48 mpz_out_str (stdout, -16, x);
49 printf ("\n y %g\n", y);
50 printf (" y");
51 for (i = 0; i < sizeof(y); i++)
52 printf (" %02X", (unsigned) ((unsigned char *) &y)[i]);
53 printf ("\n");
54 abort ();
55 }
56
57 got = mpz_cmpabs_d (x, y);
58 if (SGN(got) != cmpabs)
59 {
60 printf ("mpz_cmpabs_d wrong\n");
61 printf (" got %d\n", got);
62 printf (" want %d\n", cmpabs);
63 goto fail;
64 }
65 }
66
67 void
68 check_data (void)
69 {
70 static const struct {
71 const char *x;
72 double y;
73 int cmp, cmpabs;
74
75 } data[] = {
76
77 { "0", 0.0, 0, 0 },
78
79 { "1", 0.0, 1, 1 },
80 { "-1", 0.0, -1, 1 },
81
82 { "1", 0.5, 1, 1 },
83 { "-1", -0.5, -1, 1 },
84
85 { "0", 1.0, -1, -1 },
86 { "0", -1.0, 1, -1 },
87
88 { "0x1000000000000000000000000000000000000000000000000", 1.0, 1, 1 },
89 { "-0x1000000000000000000000000000000000000000000000000", 1.0, -1, 1 },
90
91 { "0", 1e100, -1, -1 },
92 { "0", -1e100, 1, -1 },
93
94 { "2", 1.5, 1, 1 },
95 { "2", -1.5, 1, 1 },
96 { "-2", 1.5, -1, 1 },
97 { "-2", -1.5, -1, 1 },
98 };
99
100 mpz_t x;
101 unsigned i;
102
103 mpz_init (x);
104
105 for (i = 0; i < numberof (data); i++)
106 {
107 mpz_set_str_or_abort (x, data[i].x, 0);
108 check_one ("check_data", x, data[i].y, data[i].cmp, data[i].cmpabs);
109 }
110
111 mpz_clear (x);
112 }
113
114
115 /* Equality of integers with up to 53 bits */
116 void
117 check_onebits (void)
118 {
119 mpz_t x, x2;
120 double y;
121 int i;
122
123 mpz_init_set_ui (x, 0L);
124 mpz_init (x2);
125
126 for (i = 0; i < 512; i++)
127 {
128 mpz_mul_2exp (x, x, 1);
129 mpz_add_ui (x, x, 1L);
130
131 y = mpz_get_d (x);
132 mpz_set_d (x2, y);
133
134 /* stop if any truncation is occurring */
135 if (mpz_cmp (x, x2) != 0)
136 break;
137
138 check_one ("check_onebits", x, y, 0, 0);
139 check_one ("check_onebits", x, -y, 1, 0);
140 mpz_neg (x, x);
141 check_one ("check_onebits", x, y, -1, 0);
142 check_one ("check_onebits", x, -y, 0, 0);
143 mpz_neg (x, x);
144 }
145
146 mpz_clear (x);
147 mpz_clear (x2);
148 }
149
150
151 /* With the mpz differing by 1, in a limb position possibly below the double */
152 void
153 check_low_z_one (void)
154 {
155 mpz_t x;
156 double y;
157 unsigned long i;
158
159 mpz_init (x);
160
161 /* FIXME: It'd be better to base this on the float format. */
162 #if defined (__vax) || defined (__vax__)
163 #define LIM 127 /* vax fp numbers have limited range */
164 #else
165 #define LIM 512
166 #endif
167
168 for (i = 1; i < LIM; i++)
169 {
170 mpz_set_ui (x, 1L);
171 mpz_mul_2exp (x, x, i);
172 y = mpz_get_d (x);
173
174 check_one ("check_low_z_one", x, y, 0, 0);
175 check_one ("check_low_z_one", x, -y, 1, 0);
176 mpz_neg (x, x);
177 check_one ("check_low_z_one", x, y, -1, 0);
178 check_one ("check_low_z_one", x, -y, 0, 0);
179 mpz_neg (x, x);
180
181 mpz_sub_ui (x, x, 1);
182
183 check_one ("check_low_z_one", x, y, -1, -1);
184 check_one ("check_low_z_one", x, -y, 1, -1);
185 mpz_neg (x, x);
186 check_one ("check_low_z_one", x, y, -1, -1);
187 check_one ("check_low_z_one", x, -y, 1, -1);
188 mpz_neg (x, x);
189
190 mpz_add_ui (x, x, 2);
191
192 check_one ("check_low_z_one", x, y, 1, 1);
193 check_one ("check_low_z_one", x, -y, 1, 1);
194 mpz_neg (x, x);
195 check_one ("check_low_z_one", x, y, -1, 1);
196 check_one ("check_low_z_one", x, -y, -1, 1);
197 mpz_neg (x, x);
198 }
199
200 mpz_clear (x);
201 }
202
203 /* Comparing 1 and 1+2^-n. "y" is volatile to make gcc store and fetch it,
204 which forces it to a 64-bit double, whereas on x86 it would otherwise
205 remain on the float stack as an 80-bit long double. */
206 void
207 check_one_2exp (void)
208 {
209 double e;
210 mpz_t x;
211 volatile double y;
212 int i;
213
214 mpz_init (x);
215
216 e = 1.0;
217 for (i = 0; i < 128; i++)
218 {
219 e /= 2.0;
220 y = 1.0 + e;
221 if (y == 1.0)
222 break;
223
224 mpz_set_ui (x, 1L);
225 check_one ("check_one_2exp", x, y, -1, -1);
226 check_one ("check_one_2exp", x, -y, 1, -1);
227
228 mpz_set_si (x, -1L);
229 check_one ("check_one_2exp", x, y, -1, -1);
230 check_one ("check_one_2exp", x, -y, 1, -1);
231 }
232
233 mpz_clear (x);
234 }
235
236 void
237 check_infinity (void)
238 {
239 mpz_t x;
240 double y = HUGE_VAL;
241 if (y != 2*y)
242 return;
243
244 mpz_init (x);
245
246 /* 0 cmp inf */
247 mpz_set_ui (x, 0L);
248 check_one ("check_infinity", x, y, -1, -1);
249 check_one ("check_infinity", x, -y, 1, -1);
250
251 /* 123 cmp inf */
252 mpz_set_ui (x, 123L);
253 check_one ("check_infinity", x, y, -1, -1);
254 check_one ("check_infinity", x, -y, 1, -1);
255
256 /* -123 cmp inf */
257 mpz_set_si (x, -123L);
258 check_one ("check_infinity", x, y, -1, -1);
259 check_one ("check_infinity", x, -y, 1, -1);
260
261 /* 2^5000 cmp inf */
262 mpz_set_ui (x, 1L);
263 mpz_mul_2exp (x, x, 5000L);
264 check_one ("check_infinity", x, y, -1, -1);
265 check_one ("check_infinity", x, -y, 1, -1);
266
267 /* -2^5000 cmp inf */
268 mpz_neg (x, x);
269 check_one ("check_infinity", x, y, -1, -1);
270 check_one ("check_infinity", x, -y, 1, -1);
271
272 mpz_clear (x);
273 }
274
275 void
276 testmain (int argc, char *argv[])
277 {
278 check_data ();
279 check_onebits ();
280 check_low_z_one ();
281 check_one_2exp ();
282 check_infinity ();
283 }