1 /* Test mpz_addmul, mpz_addmul_ui, mpz_submul, mpz_submul_ui.
2
3 Copyright 2001, 2002, 2022 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
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include "gmp-impl.h"
26 #include "tests.h"
27
28
29 #define M GMP_NUMB_MAX
30
31
32 void
33 check_one_inplace (mpz_srcptr w, mpz_srcptr y)
34 {
35 mpz_t want, got;
36
37 mpz_init (want);
38 mpz_init (got);
39
40 mpz_mul (want, w, y);
41 mpz_add (want, w, want);
42 mpz_set (got, w);
43 mpz_addmul (got, got, y);
44 MPZ_CHECK_FORMAT (got);
45 if (mpz_cmp (want, got) != 0)
46 {
47 printf ("mpz_addmul inplace fail\n");
48 fail:
49 mpz_trace ("w", w);
50 mpz_trace ("y", y);
51 mpz_trace ("want", want);
52 mpz_trace ("got ", got);
53 abort ();
54 }
55
56 mpz_mul (want, w, y);
57 mpz_sub (want, w, want);
58 mpz_set (got, w);
59 mpz_submul (got, got, y);
60 MPZ_CHECK_FORMAT (got);
61 if (mpz_cmp (want, got) != 0)
62 {
63 printf ("mpz_submul inplace fail\n");
64 goto fail;
65 }
66
67 mpz_clear (want);
68 mpz_clear (got);
69 }
70
71 void
72 check_one_ui_inplace (mpz_ptr w, unsigned long y)
73 {
74 mpz_t want, got;
75
76 mpz_init (want);
77 mpz_init (got);
78
79 mpz_mul_ui (want, w, (unsigned long) y);
80 mpz_add (want, w, want);
81 mpz_set (got, w);
82 mpz_addmul_ui (got, got, (unsigned long) y);
83 MPZ_CHECK_FORMAT (got);
84 if (mpz_cmp (want, got) != 0)
85 {
86 printf ("mpz_addmul_ui fail\n");
87 fail:
88 mpz_trace ("w", w);
89 printf ("y=0x%lX %lu\n", y, y);
90 mpz_trace ("want", want);
91 mpz_trace ("got ", got);
92 abort ();
93 }
94
95 mpz_mul_ui (want, w, y);
96 mpz_sub (want, w, want);
97 mpz_set (got, w);
98 mpz_submul_ui (got, got, y);
99 MPZ_CHECK_FORMAT (got);
100 if (mpz_cmp (want, got) != 0)
101 {
102 printf ("mpz_submul_ui fail\n");
103 goto fail;
104 }
105
106 mpz_clear (want);
107 mpz_clear (got);
108 }
109
110 void
111 check_all_inplace (mpz_ptr w, mpz_ptr y)
112 {
113 int wneg, yneg;
114
115 MPZ_CHECK_FORMAT (w);
116 MPZ_CHECK_FORMAT (y);
117
118 for (wneg = 0; wneg < 2; wneg++)
119 {
120 for (yneg = 0; yneg < 2; yneg++)
121 {
122 check_one_inplace (w, y);
123
124 if (mpz_fits_ulong_p (y))
125 check_one_ui_inplace (w, mpz_get_ui (y));
126
127 mpz_neg (y, y);
128 }
129 mpz_neg (w, w);
130 }
131 }
132
133 void
134 check_one (mpz_srcptr w, mpz_srcptr x, mpz_srcptr y)
135 {
136 mpz_t want, got;
137
138 mpz_init (want);
139 mpz_init (got);
140
141 mpz_mul (want, x, y);
142 mpz_add (want, w, want);
143 mpz_set (got, w);
144 mpz_addmul (got, x, y);
145 MPZ_CHECK_FORMAT (got);
146 if (mpz_cmp (want, got) != 0)
147 {
148 printf ("mpz_addmul fail\n");
149 fail:
150 mpz_trace ("w", w);
151 mpz_trace ("x", x);
152 mpz_trace ("y", y);
153 mpz_trace ("want", want);
154 mpz_trace ("got ", got);
155 abort ();
156 }
157
158
159 mpz_sub (want, want, w);
160 mpz_sub (want, w, want);
161 mpz_set (got, w);
162 mpz_submul (got, x, y);
163 MPZ_CHECK_FORMAT (got);
164 if (mpz_cmp (want, got) != 0)
165 {
166 printf ("mpz_submul fail\n");
167 goto fail;
168 }
169
170 mpz_clear (want);
171 mpz_clear (got);
172 }
173
174 void
175 check_sqr (mpz_srcptr w, mpz_srcptr x)
176 {
177 mpz_t want, got;
178
179 mpz_init (want);
180 mpz_init (got);
181
182 mpz_mul (want, x, x);
183 mpz_add (want, w, want);
184 mpz_set (got, w);
185 mpz_addmul (got, x, x);
186 MPZ_CHECK_FORMAT (got);
187 if (mpz_cmp (want, got) != 0)
188 {
189 printf ("mpz_addmul xx fail\n");
190 sqrfail:
191 mpz_trace ("w", w);
192 mpz_trace ("x", x);
193 mpz_trace ("want", want);
194 mpz_trace ("got ", got);
195 abort ();
196 }
197
198 mpz_sub (want, want, w);
199 mpz_sub (want, w, want);
200 mpz_set (got, w);
201 mpz_submul (got, x, x);
202 MPZ_CHECK_FORMAT (got);
203 if (mpz_cmp (want, got) != 0)
204 {
205 printf ("mpz_submul xx fail\n");
206 goto sqrfail;
207 }
208
209 mpz_clear (want);
210 mpz_clear (got);
211 }
212
213 void
214 check_one_ui (mpz_ptr w, mpz_ptr x, unsigned long y)
215 {
216 mpz_t want, got;
217
218 mpz_init (want);
219 mpz_init (got);
220
221 mpz_mul_ui (want, x, (unsigned long) y);
222 mpz_add (want, w, want);
223 mpz_set (got, w);
224 mpz_addmul_ui (got, x, (unsigned long) y);
225 MPZ_CHECK_FORMAT (got);
226 if (mpz_cmp (want, got) != 0)
227 {
228 printf ("mpz_addmul_ui fail\n");
229 fail:
230 mpz_trace ("w", w);
231 mpz_trace ("x", x);
232 printf ("y=0x%lX %lu\n", y, y);
233 mpz_trace ("want", want);
234 mpz_trace ("got ", got);
235 abort ();
236 }
237
238 mpz_mul_ui (want, x, y);
239 mpz_sub (want, w, want);
240 mpz_set (got, w);
241 mpz_submul_ui (got, x, y);
242 MPZ_CHECK_FORMAT (got);
243 if (mpz_cmp (want, got) != 0)
244 {
245 printf ("mpz_submul_ui fail\n");
246 goto fail;
247 }
248
249 mpz_clear (want);
250 mpz_clear (got);
251 }
252
253
254 void
255 check_all (mpz_ptr w, mpz_ptr x, mpz_ptr y)
256 {
257 int swap, wneg, xneg, yneg;
258
259 MPZ_CHECK_FORMAT (w);
260 MPZ_CHECK_FORMAT (x);
261 MPZ_CHECK_FORMAT (y);
262
263 for (swap = 0; swap < 2; swap++)
264 {
265 for (wneg = 0; wneg < 2; wneg++)
266 {
267 for (xneg = 0; xneg < 2; xneg++)
268 {
269 for (yneg = 0; yneg < 2; yneg++)
270 {
271 check_one (w, x, y);
272
273 if (mpz_fits_ulong_p (y))
274 check_one_ui (w, x, mpz_get_ui (y));
275
276 mpz_neg (y, y);
277 }
278
279 check_sqr (w, x);
280
281 mpz_neg (x, x);
282 }
283 mpz_neg (w, w);
284 }
285 mpz_swap (x, y);
286 }
287 }
288
289 void
290 check_data_inplace_ui (void)
291 {
292 static const struct {
293 mp_limb_t w[6];
294 unsigned long y;
295
296 } data[] = {
297
298 { { 0 }, 0 },
299 { { 0 }, 1 },
300 { { 1 }, 1 },
301 { { 2 }, 1 },
302
303 { { 123 }, 1 },
304 { { 123 }, ULONG_MAX },
305 { { M }, 1 },
306 { { M }, ULONG_MAX },
307
308 { { 123, 456 }, 1 },
309 { { M, M }, 1 },
310 { { 123, 456 }, ULONG_MAX },
311 { { M, M }, ULONG_MAX },
312
313 { { 123, 456, 789 }, 1 },
314 { { M, M, M }, 1 },
315 { { 123, 456, 789 }, ULONG_MAX },
316 { { M, M, M }, ULONG_MAX },
317 };
318
319 mpz_t w, y;
320 int i;
321
322 mpz_init (w);
323 mpz_init (y);
324
325 for (i = 0; i < numberof (data); i++)
326 {
327 mpz_set_n (w, data[i].w, (mp_size_t) numberof(data[i].w));
328 mpz_set_ui (y, data[i].y);
329 check_all_inplace (w, y);
330 }
331
332 mpz_clear (w);
333 mpz_clear (y);
334 }
335
336 void
337 check_data (void)
338 {
339 static const struct {
340 mp_limb_t w[6];
341 mp_limb_t x[6];
342 mp_limb_t y[6];
343
344 } data[] = {
345
346 /* reducing to zero */
347 { { 1 }, { 1 }, { 1 } },
348 { { 2 }, { 1 }, { 2 } },
349 { { 0,1 }, { 0,1 }, { 1 } },
350
351 /* reducing to 1 */
352 { { 0,1 }, { M }, { 1 } },
353 { { 0,0,1 }, { M,M }, { 1 } },
354 { { 0,0,0,1 }, { M,M,M }, { 1 } },
355 { { 0,0,0,0,1 }, { M,M,M,M }, { 1 } },
356
357 /* reducing to -1 */
358 { { M }, { 0,1 }, { 1 } },
359 { { M,M }, { 0,0,1 }, { 1 } },
360 { { M,M,M }, { 0,0,0,1 }, { 1 } },
361 { { M,M,M,M }, { 0,0,0,0,1 }, { 1 } },
362
363 /* carry out of addmul */
364 { { M }, { 1 }, { 1 } },
365 { { M,M }, { 1 }, { 1 } },
366 { { M,M,M }, { 1 }, { 1 } },
367
368 /* borrow from submul */
369 { { 0,1 }, { 1 }, { 1 } },
370 { { 0,0,1 }, { 1 }, { 1 } },
371 { { 0,0,0,1 }, { 1 }, { 1 } },
372
373 /* borrow from submul */
374 { { 0,0,1 }, { 0,1 }, { 1 } },
375 { { 0,0,0,1 }, { 0,1 }, { 1 } },
376 { { 0,0,0,0,1 }, { 0,1 }, { 1 } },
377
378 /* more borrow from submul */
379 { { M }, { 0,1 }, { 1 } },
380 { { M }, { 0,0,1 }, { 1 } },
381 { { M }, { 0,0,0,1 }, { 1 } },
382 { { M }, { 0,0,0,0,1 }, { 1 } },
383
384 /* big borrow from submul */
385 { { 0,0,1 }, { M,M }, { M } },
386 { { 0,0,0,1 }, { M,M }, { M } },
387 { { 0,0,0,0,1 }, { M,M }, { M } },
388
389 /* small w */
390 { { 0,1 }, { M,M }, { M } },
391 { { 0,1 }, { M,M,M }, { M } },
392 { { 0,1 }, { M,M,M,M }, { M } },
393 { { 0,1 }, { M,M,M,M,M }, { M } },
394 };
395
396 mpz_t w, x, y;
397 int i;
398
399 mpz_init (w);
400 mpz_init (x);
401 mpz_init (y);
402
403 for (i = 0; i < numberof (data); i++)
404 {
405 mpz_set_n (w, data[i].w, (mp_size_t) numberof(data[i].w));
406 mpz_set_n (x, data[i].x, (mp_size_t) numberof(data[i].x));
407 mpz_set_n (y, data[i].y, (mp_size_t) numberof(data[i].y));
408 check_all (w, x, y);
409 }
410
411 mpz_clear (w);
412 mpz_clear (x);
413 mpz_clear (y);
414 }
415
416
417 void
418 check_random (int argc, char *argv[])
419 {
420 gmp_randstate_ptr rands = RANDS;
421 mpz_t w, x, y;
422 int i, reps = 2000;
423
424 mpz_init (w);
425 mpz_init (x);
426 mpz_init (y);
427
428 if (argc == 2)
429 reps = atoi (argv[1]);
430
431 for (i = 0; i < reps; i++)
432 {
433 mpz_errandomb (w, rands, 5*GMP_LIMB_BITS);
434 mpz_errandomb (x, rands, 5*GMP_LIMB_BITS);
435 mpz_errandomb (y, rands, 5*GMP_LIMB_BITS);
436 check_all (w, x, y);
437 check_all_inplace (w, y);
438
439 mpz_errandomb (w, rands, 5*GMP_LIMB_BITS);
440 mpz_errandomb (x, rands, 5*GMP_LIMB_BITS);
441 mpz_errandomb (y, rands, BITS_PER_ULONG);
442 check_all (w, x, y);
443 check_all_inplace (w, y);
444 }
445
446 mpz_clear (w);
447 mpz_clear (x);
448 mpz_clear (y);
449 }
450
451
452 int
453 main (int argc, char *argv[])
454 {
455 tests_start ();
456 mp_trace_base = -16;
457
458 check_data ();
459 check_data_inplace_ui ();
460 check_random (argc, argv);
461
462 tests_end ();
463 exit (0);
464 }