1/* Test for mullo function.
2
3Copyright 2009 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 "gmp.h"
22#include "gmp-impl.h"
23#include "tests.h"
24
25#include <stdlib.h>
26#include <stdio.h>
27
28/* Sizes are up to 2^SIZE_LOG limbs */
29#ifndef SIZE_LOG
30#define SIZE_LOG 10
31#endif
32
33#ifndef COUNT
34#define COUNT 10000
35#endif
36
37#define MAX_N (1L << SIZE_LOG)
38#define MIN_N (1)
39
40int
41main (int argc, char **argv)
42{
43  mp_ptr ap, bp, refp, pp, scratch;
44  int count = COUNT;
45  int test;
46  gmp_randstate_ptr rands;
47  TMP_DECL;
48  TMP_MARK;
49
50  if (argc > 1)
51    {
52      char *end;
53      count = strtol (argv[1], &end, 0);
54      if (*end || count <= 0)
55	{
56	  fprintf (stderr, "Invalid test count: %s.\n", argv[1]);
57	  return 1;
58	}
59    }
60
61  tests_start ();
62  rands = RANDS;
63
64#define mpn_mullo_itch(n) (0)
65
66  ap = TMP_ALLOC_LIMBS (MAX_N);
67  bp = TMP_ALLOC_LIMBS (MAX_N);
68  refp = TMP_ALLOC_LIMBS (MAX_N * 2);
69  pp = 1+TMP_ALLOC_LIMBS (MAX_N + 2);
70  scratch
71    = 1+TMP_ALLOC_LIMBS (mpn_mullo_itch (MAX_N) + 2);
72
73  for (test = 0; test < count; test++)
74    {
75      unsigned size_min;
76      unsigned size_range;
77      mp_size_t n;
78      mp_size_t itch;
79      mp_limb_t p_before, p_after, s_before, s_after;
80
81      for (size_min = 1; (1L << size_min) < MIN_N; size_min++)
82	;
83
84      /* We generate an in the MIN_N <= n <= (1 << size_range). */
85      size_range = size_min
86	+ gmp_urandomm_ui (rands, SIZE_LOG + 1 - size_min);
87
88      n = MIN_N
89	+ gmp_urandomm_ui (rands, (1L << size_range) + 1 - MIN_N);
90
91      mpn_random2 (ap, n);
92      mpn_random2 (bp, n);
93      mpn_random2 (pp-1, n + 2);
94      p_before = pp[-1];
95      p_after = pp[n];
96
97      itch = mpn_mullo_itch (n);
98      ASSERT_ALWAYS (itch <= mpn_mullo_itch (MAX_N));
99      mpn_random2 (scratch-1, itch+2);
100      s_before = scratch[-1];
101      s_after = scratch[itch];
102
103      mpn_mullo_n (pp, ap, bp, n);
104      mpn_mul_n (refp, ap, bp, n);
105      if (pp[-1] != p_before || pp[n] != p_after
106	  || scratch[-1] != s_before || scratch[itch] != s_after
107	  || mpn_cmp (refp, pp, n) != 0)
108	{
109	  printf ("ERROR in test %d, n = %d",
110		  test, (int) n);
111	  if (pp[-1] != p_before)
112	    {
113	      printf ("before pp:"); mpn_dump (pp -1, 1);
114	      printf ("keep:   "); mpn_dump (&p_before, 1);
115	    }
116	  if (pp[n] != p_after)
117	    {
118	      printf ("after pp:"); mpn_dump (pp + n, 1);
119	      printf ("keep:   "); mpn_dump (&p_after, 1);
120	    }
121	  if (scratch[-1] != s_before)
122	    {
123	      printf ("before scratch:"); mpn_dump (scratch-1, 1);
124	      printf ("keep:   "); mpn_dump (&s_before, 1);
125	    }
126	  if (scratch[itch] != s_after)
127	    {
128	      printf ("after scratch:"); mpn_dump (scratch + itch, 1);
129	      printf ("keep:   "); mpn_dump (&s_after, 1);
130	    }
131	  mpn_dump (ap, n);
132	  mpn_dump (bp, n);
133	  mpn_dump (pp, n);
134	  mpn_dump (refp, n);
135
136	  abort();
137	}
138    }
139  TMP_FREE;
140  tests_end ();
141  return 0;
142}
143