1/* Test mpz_addmul, mpz_addmul_ui, mpz_submul, mpz_submul_ui.
2
3Copyright 2001, 2002 Free Software Foundation, Inc.
4
5This file is part of the GNU MP Library test suite.
6
7The GNU MP Library test suite is free software; you can redistribute it
8and/or modify it under the terms of the GNU General Public License as
9published by the Free Software Foundation; either version 3 of the License,
10or (at your option) any later version.
11
12The GNU MP Library test suite is distributed in the hope that it will be
13useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
15Public License for more details.
16
17You should have received a copy of the GNU General Public License along with
18the 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
32void
33check_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
71void
72check_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
110void
111check_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
133void
134check_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  mpz_mul (want, x, y);
159  mpz_sub (want, w, want);
160  mpz_set (got, w);
161  mpz_submul (got, x, y);
162  MPZ_CHECK_FORMAT (got);
163  if (mpz_cmp (want, got) != 0)
164    {
165      printf ("mpz_submul fail\n");
166      goto fail;
167    }
168
169  mpz_clear (want);
170  mpz_clear (got);
171}
172
173void
174check_one_ui (mpz_ptr w, mpz_ptr x, unsigned long y)
175{
176  mpz_t  want, got;
177
178  mpz_init (want);
179  mpz_init (got);
180
181  mpz_mul_ui (want, x, (unsigned long) y);
182  mpz_add (want, w, want);
183  mpz_set (got, w);
184  mpz_addmul_ui (got, x, (unsigned long) y);
185  MPZ_CHECK_FORMAT (got);
186  if (mpz_cmp (want, got) != 0)
187    {
188      printf ("mpz_addmul_ui fail\n");
189    fail:
190      mpz_trace ("w", w);
191      mpz_trace ("x", x);
192      printf    ("y=0x%lX   %lu\n", y, y);
193      mpz_trace ("want", want);
194      mpz_trace ("got ", got);
195      abort ();
196    }
197
198  mpz_mul_ui (want, x, y);
199  mpz_sub (want, w, want);
200  mpz_set (got, w);
201  mpz_submul_ui (got, x, y);
202  MPZ_CHECK_FORMAT (got);
203  if (mpz_cmp (want, got) != 0)
204    {
205      printf ("mpz_submul_ui fail\n");
206      goto fail;
207    }
208
209  mpz_clear (want);
210  mpz_clear (got);
211}
212
213
214void
215check_all (mpz_ptr w, mpz_ptr x, mpz_ptr y)
216{
217  int    swap, wneg, xneg, yneg;
218
219  MPZ_CHECK_FORMAT (w);
220  MPZ_CHECK_FORMAT (x);
221  MPZ_CHECK_FORMAT (y);
222
223  for (swap = 0; swap < 2; swap++)
224    {
225      for (wneg = 0; wneg < 2; wneg++)
226        {
227          for (xneg = 0; xneg < 2; xneg++)
228            {
229              for (yneg = 0; yneg < 2; yneg++)
230                {
231                  check_one (w, x, y);
232
233                  if (mpz_fits_ulong_p (y))
234                    check_one_ui (w, x, mpz_get_ui (y));
235
236                  mpz_neg (y, y);
237                }
238              mpz_neg (x, x);
239            }
240          mpz_neg (w, w);
241        }
242      mpz_swap (x, y);
243    }
244}
245
246void
247check_data_inplace_ui (void)
248{
249  static const struct {
250    mp_limb_t      w[6];
251    unsigned long  y;
252
253  } data[] = {
254
255    { { 0 }, 0 },
256    { { 0 }, 1 },
257    { { 1 }, 1 },
258    { { 2 }, 1 },
259
260    { { 123 }, 1 },
261    { { 123 }, ULONG_MAX },
262    { { M }, 1 },
263    { { M }, ULONG_MAX },
264
265    { { 123, 456 }, 1 },
266    { { M, M }, 1 },
267    { { 123, 456 }, ULONG_MAX },
268    { { M, M }, ULONG_MAX },
269
270    { { 123, 456, 789 }, 1 },
271    { { M, M, M }, 1 },
272    { { 123, 456, 789 }, ULONG_MAX },
273    { { M, M, M }, ULONG_MAX },
274  };
275
276  mpz_t  w, y;
277  int    i;
278
279  mpz_init (w);
280  mpz_init (y);
281
282  for (i = 0; i < numberof (data); i++)
283    {
284      mpz_set_n (w, data[i].w, (mp_size_t) numberof(data[i].w));
285      mpz_set_ui (y, data[i].y);
286      check_all_inplace (w, y);
287    }
288
289  mpz_clear (w);
290  mpz_clear (y);
291}
292
293void
294check_data (void)
295{
296  static const struct {
297    mp_limb_t  w[6];
298    mp_limb_t  x[6];
299    mp_limb_t  y[6];
300
301  } data[] = {
302
303    /* reducing to zero */
304    { { 1 }, { 1 }, { 1 } },
305    { { 2 }, { 1 }, { 2 } },
306    { { 0,1 }, { 0,1 }, { 1 } },
307
308    /* reducing to 1 */
309    { { 0,1 },       { M },       { 1 } },
310    { { 0,0,1 },     { M,M },     { 1 } },
311    { { 0,0,0,1 },   { M,M,M },   { 1 } },
312    { { 0,0,0,0,1 }, { M,M,M,M }, { 1 } },
313
314    /* reducing to -1 */
315    { { M },       { 0,1 },       { 1 } },
316    { { M,M },     { 0,0,1 },     { 1 } },
317    { { M,M,M },   { 0,0,0,1 },   { 1 } },
318    { { M,M,M,M }, { 0,0,0,0,1 }, { 1 } },
319
320    /* carry out of addmul */
321    { { M },     { 1 }, { 1 } },
322    { { M,M },   { 1 }, { 1 } },
323    { { M,M,M }, { 1 }, { 1 } },
324
325    /* borrow from submul */
326    { { 0,1 },     { 1 }, { 1 } },
327    { { 0,0,1 },   { 1 }, { 1 } },
328    { { 0,0,0,1 }, { 1 }, { 1 } },
329
330    /* borrow from submul */
331    { { 0,0,1 },     { 0,1 }, { 1 } },
332    { { 0,0,0,1 },   { 0,1 }, { 1 } },
333    { { 0,0,0,0,1 }, { 0,1 }, { 1 } },
334
335    /* more borrow from submul */
336    { { M }, { 0,1 },       { 1 } },
337    { { M }, { 0,0,1 },     { 1 } },
338    { { M }, { 0,0,0,1 },   { 1 } },
339    { { M }, { 0,0,0,0,1 }, { 1 } },
340
341    /* big borrow from submul */
342    { { 0,0,1 },     { M,M }, { M } },
343    { { 0,0,0,1 },   { M,M }, { M } },
344    { { 0,0,0,0,1 }, { M,M }, { M } },
345
346    /* small w */
347    { { 0,1 }, { M,M },       { M } },
348    { { 0,1 }, { M,M,M },     { M } },
349    { { 0,1 }, { M,M,M,M },   { M } },
350    { { 0,1 }, { M,M,M,M,M }, { M } },
351  };
352
353  mpz_t  w, x, y;
354  int    i;
355
356  mpz_init (w);
357  mpz_init (x);
358  mpz_init (y);
359
360  for (i = 0; i < numberof (data); i++)
361    {
362      mpz_set_n (w, data[i].w, (mp_size_t) numberof(data[i].w));
363      mpz_set_n (x, data[i].x, (mp_size_t) numberof(data[i].x));
364      mpz_set_n (y, data[i].y, (mp_size_t) numberof(data[i].y));
365      check_all (w, x, y);
366    }
367
368  mpz_clear (w);
369  mpz_clear (x);
370  mpz_clear (y);
371}
372
373
374void
375check_random (int argc, char *argv[])
376{
377  gmp_randstate_ptr rands = RANDS;
378  mpz_t  w, x, y;
379  int    i, reps = 2000;
380
381  mpz_init (w);
382  mpz_init (x);
383  mpz_init (y);
384
385  if (argc == 2)
386    reps = atoi (argv[1]);
387
388  for (i = 0; i < reps; i++)
389    {
390      mpz_errandomb (w, rands, 5*GMP_LIMB_BITS);
391      mpz_errandomb (x, rands, 5*GMP_LIMB_BITS);
392      mpz_errandomb (y, rands, 5*GMP_LIMB_BITS);
393      check_all (w, x, y);
394      check_all_inplace (w, y);
395
396      mpz_errandomb (w, rands, 5*GMP_LIMB_BITS);
397      mpz_errandomb (x, rands, 5*GMP_LIMB_BITS);
398      mpz_errandomb (y, rands, BITS_PER_ULONG);
399      check_all (w, x, y);
400      check_all_inplace (w, y);
401    }
402
403  mpz_clear (w);
404  mpz_clear (x);
405  mpz_clear (y);
406}
407
408
409int
410main (int argc, char *argv[])
411{
412  tests_start ();
413  mp_trace_base = -16;
414
415  check_data ();
416  check_data_inplace_ui ();
417  check_random (argc, argv);
418
419  tests_end ();
420  exit (0);
421}
422