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.
6
7The GNU MP Library is free software; you can redistribute it and/or modify
8it under the terms of the GNU Lesser General Public License as published by
9the Free Software Foundation; either version 3 of the License, or (at your
10option) any later version.
11
12The GNU MP Library is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
15License for more details.
16
17You should have received a copy of the GNU Lesser General Public License
18along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */
19
20
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24
25#include "gmp.h"
26#include "gmp-impl.h"
27#include "tests.h"
28
29
30#define M GMP_NUMB_MAX
31
32
33void
34check_one_inplace (mpz_srcptr w, mpz_srcptr y)
35{
36  mpz_t  want, got;
37
38  mpz_init (want);
39  mpz_init (got);
40
41  mpz_mul (want, w, y);
42  mpz_add (want, w, want);
43  mpz_set (got, w);
44  mpz_addmul (got, got, y);
45  MPZ_CHECK_FORMAT (got);
46  if (mpz_cmp (want, got) != 0)
47    {
48      printf ("mpz_addmul inplace fail\n");
49    fail:
50      mpz_trace ("w", w);
51      mpz_trace ("y", y);
52      mpz_trace ("want", want);
53      mpz_trace ("got ", got);
54      abort ();
55    }
56
57  mpz_mul (want, w, y);
58  mpz_sub (want, w, want);
59  mpz_set (got, w);
60  mpz_submul (got, got, y);
61  MPZ_CHECK_FORMAT (got);
62  if (mpz_cmp (want, got) != 0)
63    {
64      printf ("mpz_submul inplace fail\n");
65      goto fail;
66    }
67
68  mpz_clear (want);
69  mpz_clear (got);
70}
71
72void
73check_one_ui_inplace (mpz_ptr w, unsigned long y)
74{
75  mpz_t  want, got;
76
77  mpz_init (want);
78  mpz_init (got);
79
80  mpz_mul_ui (want, w, (unsigned long) y);
81  mpz_add (want, w, want);
82  mpz_set (got, w);
83  mpz_addmul_ui (got, got, (unsigned long) y);
84  MPZ_CHECK_FORMAT (got);
85  if (mpz_cmp (want, got) != 0)
86    {
87      printf ("mpz_addmul_ui fail\n");
88    fail:
89      mpz_trace ("w", w);
90      printf    ("y=0x%lX   %lu\n", y, y);
91      mpz_trace ("want", want);
92      mpz_trace ("got ", got);
93      abort ();
94    }
95
96  mpz_mul_ui (want, w, y);
97  mpz_sub (want, w, want);
98  mpz_set (got, w);
99  mpz_submul_ui (got, got, y);
100  MPZ_CHECK_FORMAT (got);
101  if (mpz_cmp (want, got) != 0)
102    {
103      printf ("mpz_submul_ui fail\n");
104      goto fail;
105    }
106
107  mpz_clear (want);
108  mpz_clear (got);
109}
110
111void
112check_all_inplace (mpz_ptr w, mpz_ptr y)
113{
114  int  wneg, yneg;
115
116  MPZ_CHECK_FORMAT (w);
117  MPZ_CHECK_FORMAT (y);
118
119  for (wneg = 0; wneg < 2; wneg++)
120    {
121      for (yneg = 0; yneg < 2; yneg++)
122        {
123          check_one_inplace (w, y);
124
125          if (mpz_fits_ulong_p (y))
126            check_one_ui_inplace (w, mpz_get_ui (y));
127
128          mpz_neg (y, y);
129        }
130      mpz_neg (w, w);
131    }
132}
133
134void
135check_one (mpz_srcptr w, mpz_srcptr x, mpz_srcptr y)
136{
137  mpz_t  want, got;
138
139  mpz_init (want);
140  mpz_init (got);
141
142  mpz_mul (want, x, y);
143  mpz_add (want, w, want);
144  mpz_set (got, w);
145  mpz_addmul (got, x, y);
146  MPZ_CHECK_FORMAT (got);
147  if (mpz_cmp (want, got) != 0)
148    {
149      printf ("mpz_addmul fail\n");
150    fail:
151      mpz_trace ("w", w);
152      mpz_trace ("x", x);
153      mpz_trace ("y", y);
154      mpz_trace ("want", want);
155      mpz_trace ("got ", got);
156      abort ();
157    }
158
159  mpz_mul (want, x, y);
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
174void
175check_one_ui (mpz_ptr w, mpz_ptr x, unsigned long y)
176{
177  mpz_t  want, got;
178
179  mpz_init (want);
180  mpz_init (got);
181
182  mpz_mul_ui (want, x, (unsigned long) y);
183  mpz_add (want, w, want);
184  mpz_set (got, w);
185  mpz_addmul_ui (got, x, (unsigned long) y);
186  MPZ_CHECK_FORMAT (got);
187  if (mpz_cmp (want, got) != 0)
188    {
189      printf ("mpz_addmul_ui fail\n");
190    fail:
191      mpz_trace ("w", w);
192      mpz_trace ("x", x);
193      printf    ("y=0x%lX   %lu\n", y, y);
194      mpz_trace ("want", want);
195      mpz_trace ("got ", got);
196      abort ();
197    }
198
199  mpz_mul_ui (want, x, y);
200  mpz_sub (want, w, want);
201  mpz_set (got, w);
202  mpz_submul_ui (got, x, y);
203  MPZ_CHECK_FORMAT (got);
204  if (mpz_cmp (want, got) != 0)
205    {
206      printf ("mpz_submul_ui fail\n");
207      goto fail;
208    }
209
210  mpz_clear (want);
211  mpz_clear (got);
212}
213
214
215void
216check_all (mpz_ptr w, mpz_ptr x, mpz_ptr y)
217{
218  int    swap, wneg, xneg, yneg;
219
220  MPZ_CHECK_FORMAT (w);
221  MPZ_CHECK_FORMAT (x);
222  MPZ_CHECK_FORMAT (y);
223
224  for (swap = 0; swap < 2; swap++)
225    {
226      for (wneg = 0; wneg < 2; wneg++)
227        {
228          for (xneg = 0; xneg < 2; xneg++)
229            {
230              for (yneg = 0; yneg < 2; yneg++)
231                {
232                  check_one (w, x, y);
233
234                  if (mpz_fits_ulong_p (y))
235                    check_one_ui (w, x, mpz_get_ui (y));
236
237                  mpz_neg (y, y);
238                }
239              mpz_neg (x, x);
240            }
241          mpz_neg (w, w);
242        }
243      mpz_swap (x, y);
244    }
245}
246
247void
248check_data_inplace_ui (void)
249{
250  static const struct {
251    mp_limb_t      w[6];
252    unsigned long  y;
253
254  } data[] = {
255
256    { { 0 }, 0 },
257    { { 0 }, 1 },
258    { { 1 }, 1 },
259    { { 2 }, 1 },
260
261    { { 123 }, 1 },
262    { { 123 }, ULONG_MAX },
263    { { M }, 1 },
264    { { M }, ULONG_MAX },
265
266    { { 123, 456 }, 1 },
267    { { M, M }, 1 },
268    { { 123, 456 }, ULONG_MAX },
269    { { M, M }, ULONG_MAX },
270
271    { { 123, 456, 789 }, 1 },
272    { { M, M, M }, 1 },
273    { { 123, 456, 789 }, ULONG_MAX },
274    { { M, M, M }, ULONG_MAX },
275  };
276
277  mpz_t  w, y;
278  int    i;
279
280  mpz_init (w);
281  mpz_init (y);
282
283  for (i = 0; i < numberof (data); i++)
284    {
285      mpz_set_n (w, data[i].w, (mp_size_t) numberof(data[i].w));
286      mpz_set_ui (y, data[i].y);
287      check_all_inplace (w, y);
288    }
289
290  mpz_clear (w);
291  mpz_clear (y);
292}
293
294void
295check_data (void)
296{
297  static const struct {
298    mp_limb_t  w[6];
299    mp_limb_t  x[6];
300    mp_limb_t  y[6];
301
302  } data[] = {
303
304    /* reducing to zero */
305    { { 1 }, { 1 }, { 1 } },
306    { { 2 }, { 1 }, { 2 } },
307    { { 0,1 }, { 0,1 }, { 1 } },
308
309    /* reducing to 1 */
310    { { 0,1 },       { M },       { 1 } },
311    { { 0,0,1 },     { M,M },     { 1 } },
312    { { 0,0,0,1 },   { M,M,M },   { 1 } },
313    { { 0,0,0,0,1 }, { M,M,M,M }, { 1 } },
314
315    /* reducing to -1 */
316    { { M },       { 0,1 },       { 1 } },
317    { { M,M },     { 0,0,1 },     { 1 } },
318    { { M,M,M },   { 0,0,0,1 },   { 1 } },
319    { { M,M,M,M }, { 0,0,0,0,1 }, { 1 } },
320
321    /* carry out of addmul */
322    { { M },     { 1 }, { 1 } },
323    { { M,M },   { 1 }, { 1 } },
324    { { M,M,M }, { 1 }, { 1 } },
325
326    /* borrow from submul */
327    { { 0,1 },     { 1 }, { 1 } },
328    { { 0,0,1 },   { 1 }, { 1 } },
329    { { 0,0,0,1 }, { 1 }, { 1 } },
330
331    /* borrow from submul */
332    { { 0,0,1 },     { 0,1 }, { 1 } },
333    { { 0,0,0,1 },   { 0,1 }, { 1 } },
334    { { 0,0,0,0,1 }, { 0,1 }, { 1 } },
335
336    /* more borrow from submul */
337    { { M }, { 0,1 },       { 1 } },
338    { { M }, { 0,0,1 },     { 1 } },
339    { { M }, { 0,0,0,1 },   { 1 } },
340    { { M }, { 0,0,0,0,1 }, { 1 } },
341
342    /* big borrow from submul */
343    { { 0,0,1 },     { M,M }, { M } },
344    { { 0,0,0,1 },   { M,M }, { M } },
345    { { 0,0,0,0,1 }, { M,M }, { M } },
346
347    /* small w */
348    { { 0,1 }, { M,M },       { M } },
349    { { 0,1 }, { M,M,M },     { M } },
350    { { 0,1 }, { M,M,M,M },   { M } },
351    { { 0,1 }, { M,M,M,M,M }, { M } },
352  };
353
354  mpz_t  w, x, y;
355  int    i;
356
357  mpz_init (w);
358  mpz_init (x);
359  mpz_init (y);
360
361  for (i = 0; i < numberof (data); i++)
362    {
363      mpz_set_n (w, data[i].w, (mp_size_t) numberof(data[i].w));
364      mpz_set_n (x, data[i].x, (mp_size_t) numberof(data[i].x));
365      mpz_set_n (y, data[i].y, (mp_size_t) numberof(data[i].y));
366      check_all (w, x, y);
367    }
368
369  mpz_clear (w);
370  mpz_clear (x);
371  mpz_clear (y);
372}
373
374
375void
376check_random (int argc, char *argv[])
377{
378  gmp_randstate_ptr rands = RANDS;
379  mpz_t  w, x, y;
380  int    i, reps = 2000;
381
382  mpz_init (w);
383  mpz_init (x);
384  mpz_init (y);
385
386  if (argc == 2)
387    reps = atoi (argv[1]);
388
389  for (i = 0; i < reps; i++)
390    {
391      mpz_errandomb (w, rands, 5*GMP_LIMB_BITS);
392      mpz_errandomb (x, rands, 5*GMP_LIMB_BITS);
393      mpz_errandomb (y, rands, 5*GMP_LIMB_BITS);
394      check_all (w, x, y);
395      check_all_inplace (w, y);
396
397      mpz_errandomb (w, rands, 5*GMP_LIMB_BITS);
398      mpz_errandomb (x, rands, 5*GMP_LIMB_BITS);
399      mpz_errandomb (y, rands, BITS_PER_ULONG);
400      check_all (w, x, y);
401      check_all_inplace (w, y);
402    }
403
404  mpz_clear (w);
405  mpz_clear (x);
406  mpz_clear (y);
407}
408
409
410int
411main (int argc, char *argv[])
412{
413  tests_start ();
414  mp_trace_base = -16;
415
416  check_data ();
417  check_data_inplace_ui ();
418  check_random (argc, argv);
419
420  tests_end ();
421  exit (0);
422}
423