t-mulmod_bnm1.c revision 1.1.1.2 1 1.1 mrg /* Test for mulmod_bnm1 function.
2 1.1 mrg
3 1.1 mrg Contributed to the GNU project by Marco Bodrato.
4 1.1 mrg
5 1.1 mrg Copyright 2009 Free Software Foundation, Inc.
6 1.1 mrg
7 1.1.1.2 mrg This file is part of the GNU MP Library test suite.
8 1.1 mrg
9 1.1.1.2 mrg The GNU MP Library test suite is free software; you can redistribute it
10 1.1.1.2 mrg and/or modify it under the terms of the GNU General Public License as
11 1.1.1.2 mrg published by the Free Software Foundation; either version 3 of the License,
12 1.1.1.2 mrg or (at your option) any later version.
13 1.1.1.2 mrg
14 1.1.1.2 mrg The GNU MP Library test suite is distributed in the hope that it will be
15 1.1.1.2 mrg useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
16 1.1.1.2 mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
17 1.1.1.2 mrg Public License for more details.
18 1.1 mrg
19 1.1.1.2 mrg You should have received a copy of the GNU General Public License along with
20 1.1.1.2 mrg the GNU MP Library test suite. If not, see http://www.gnu.org/licenses/. */
21 1.1 mrg
22 1.1 mrg
23 1.1.1.2 mrg #include <stdlib.h>
24 1.1.1.2 mrg #include <stdio.h>
25 1.1.1.2 mrg
26 1.1 mrg #include "gmp.h"
27 1.1 mrg #include "gmp-impl.h"
28 1.1 mrg #include "tests.h"
29 1.1 mrg
30 1.1 mrg /* Sizes are up to 2^SIZE_LOG limbs */
31 1.1 mrg #ifndef SIZE_LOG
32 1.1 mrg #define SIZE_LOG 11
33 1.1 mrg #endif
34 1.1 mrg
35 1.1 mrg #ifndef COUNT
36 1.1 mrg #define COUNT 5000
37 1.1 mrg #endif
38 1.1 mrg
39 1.1 mrg #define MAX_N (1L << SIZE_LOG)
40 1.1 mrg #define MIN_N 1
41 1.1 mrg
42 1.1 mrg /*
43 1.1 mrg Reference function for multiplication modulo B^rn-1.
44 1.1 mrg
45 1.1 mrg The result is expected to be ZERO if and only if one of the operand
46 1.1 mrg already is. Otherwise the class [0] Mod(B^rn-1) is represented by
47 1.1 mrg B^rn-1. This should not be a problem if mulmod_bnm1 is used to
48 1.1 mrg combine results and obtain a natural number when one knows in
49 1.1 mrg advance that the final value is less than (B^rn-1).
50 1.1 mrg */
51 1.1 mrg
52 1.1 mrg static void
53 1.1 mrg ref_mulmod_bnm1 (mp_ptr rp, mp_size_t rn, mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn)
54 1.1 mrg {
55 1.1 mrg mp_limb_t cy;
56 1.1 mrg
57 1.1 mrg ASSERT (0 < an && an <= rn);
58 1.1 mrg ASSERT (0 < bn && bn <= rn);
59 1.1 mrg
60 1.1 mrg if (an >= bn)
61 1.1 mrg refmpn_mul (rp, ap, an, bp, bn);
62 1.1 mrg else
63 1.1 mrg refmpn_mul (rp, bp, bn, ap, an);
64 1.1 mrg an += bn;
65 1.1 mrg if (an > rn) {
66 1.1 mrg cy = mpn_add (rp, rp, rn, rp + rn, an - rn);
67 1.1 mrg /* If cy == 1, then the value of rp is at most B^rn - 2, so there can
68 1.1 mrg * be no overflow when adding in the carry. */
69 1.1 mrg MPN_INCR_U (rp, rn, cy);
70 1.1 mrg }
71 1.1 mrg }
72 1.1 mrg
73 1.1 mrg /*
74 1.1 mrg Compare the result of the mpn_mulmod_bnm1 function in the library
75 1.1 mrg with the reference function above.
76 1.1 mrg */
77 1.1 mrg
78 1.1 mrg int
79 1.1 mrg main (int argc, char **argv)
80 1.1 mrg {
81 1.1 mrg mp_ptr ap, bp, refp, pp, scratch;
82 1.1 mrg int count = COUNT;
83 1.1 mrg int test;
84 1.1 mrg gmp_randstate_ptr rands;
85 1.1 mrg TMP_DECL;
86 1.1 mrg TMP_MARK;
87 1.1 mrg
88 1.1 mrg if (argc > 1)
89 1.1 mrg {
90 1.1 mrg char *end;
91 1.1 mrg count = strtol (argv[1], &end, 0);
92 1.1 mrg if (*end || count <= 0)
93 1.1 mrg {
94 1.1 mrg fprintf (stderr, "Invalid test count: %s.\n", argv[1]);
95 1.1 mrg return 1;
96 1.1 mrg }
97 1.1 mrg }
98 1.1 mrg
99 1.1 mrg tests_start ();
100 1.1 mrg rands = RANDS;
101 1.1 mrg
102 1.1 mrg ASSERT_ALWAYS (mpn_mulmod_bnm1_next_size (MAX_N) == MAX_N);
103 1.1 mrg
104 1.1 mrg ap = TMP_ALLOC_LIMBS (MAX_N);
105 1.1 mrg bp = TMP_ALLOC_LIMBS (MAX_N);
106 1.1 mrg refp = TMP_ALLOC_LIMBS (MAX_N * 4);
107 1.1 mrg pp = 1+TMP_ALLOC_LIMBS (MAX_N + 2);
108 1.1 mrg scratch
109 1.1 mrg = 1+TMP_ALLOC_LIMBS (mpn_mulmod_bnm1_itch (MAX_N, MAX_N, MAX_N) + 2);
110 1.1 mrg
111 1.1 mrg for (test = 0; test < count; test++)
112 1.1 mrg {
113 1.1 mrg unsigned size_min;
114 1.1 mrg unsigned size_range;
115 1.1 mrg mp_size_t an,bn,rn,n;
116 1.1 mrg mp_size_t itch;
117 1.1 mrg mp_limb_t p_before, p_after, s_before, s_after;
118 1.1 mrg
119 1.1 mrg for (size_min = 1; (1L << size_min) < MIN_N; size_min++)
120 1.1 mrg ;
121 1.1 mrg
122 1.1 mrg /* We generate an in the MIN_N <= n <= (1 << size_range). */
123 1.1 mrg size_range = size_min
124 1.1 mrg + gmp_urandomm_ui (rands, SIZE_LOG + 1 - size_min);
125 1.1 mrg
126 1.1 mrg n = MIN_N
127 1.1 mrg + gmp_urandomm_ui (rands, (1L << size_range) + 1 - MIN_N);
128 1.1 mrg n = mpn_mulmod_bnm1_next_size (n);
129 1.1 mrg
130 1.1 mrg if ( (test & 1) || n == 1) {
131 1.1 mrg /* Half of the tests are done with the main scenario in mind:
132 1.1 mrg both an and bn >= rn/2 */
133 1.1 mrg an = ((n+1) >> 1) + gmp_urandomm_ui (rands, (n+1) >> 1);
134 1.1 mrg bn = ((n+1) >> 1) + gmp_urandomm_ui (rands, (n+1) >> 1);
135 1.1 mrg } else {
136 1.1 mrg /* Second half of the tests are done using mulmod to compute a
137 1.1 mrg full product with n/2 < an+bn <= n. */
138 1.1 mrg an = 1 + gmp_urandomm_ui (rands, n - 1);
139 1.1 mrg if (an >= n/2)
140 1.1 mrg bn = 1 + gmp_urandomm_ui (rands, n - an);
141 1.1 mrg else
142 1.1 mrg bn = n/2 + 1 - an + gmp_urandomm_ui (rands, (n+1)/2);
143 1.1 mrg }
144 1.1 mrg
145 1.1 mrg /* Make sure an >= bn */
146 1.1 mrg if (an < bn)
147 1.1 mrg MP_SIZE_T_SWAP (an, bn);
148 1.1 mrg
149 1.1 mrg mpn_random2 (ap, an);
150 1.1 mrg mpn_random2 (bp, bn);
151 1.1 mrg
152 1.1 mrg /* Sometime trigger the borderline conditions
153 1.1 mrg A = -1,0,+1 or B = -1,0,+1 or A*B == -1,0,1 Mod(B^{n/2}+1).
154 1.1 mrg This only makes sense if there is at least a split, i.e. n is even. */
155 1.1 mrg if ((test & 0x1f) == 1 && (n & 1) == 0) {
156 1.1 mrg mp_size_t x;
157 1.1 mrg MPN_COPY (ap, ap + (n >> 1), an - (n >> 1));
158 1.1 mrg MPN_ZERO (ap + an - (n >> 1) , n - an);
159 1.1 mrg MPN_COPY (bp, bp + (n >> 1), bn - (n >> 1));
160 1.1 mrg MPN_ZERO (bp + bn - (n >> 1) , n - bn);
161 1.1 mrg x = (n == an) ? 0 : gmp_urandomm_ui (rands, n - an);
162 1.1 mrg ap[x] += gmp_urandomm_ui (rands, 3) - 1;
163 1.1 mrg x = (n >> 1) - x % (n >> 1);
164 1.1 mrg bp[x] += gmp_urandomm_ui (rands, 3) - 1;
165 1.1 mrg /* We don't propagate carry, this means that the desired condition
166 1.1 mrg is not triggered all the times. A few times are enough anyway. */
167 1.1 mrg }
168 1.1 mrg rn = MIN(n, an + bn);
169 1.1 mrg mpn_random2 (pp-1, rn + 2);
170 1.1 mrg p_before = pp[-1];
171 1.1 mrg p_after = pp[rn];
172 1.1 mrg
173 1.1 mrg itch = mpn_mulmod_bnm1_itch (n, an, bn);
174 1.1 mrg ASSERT_ALWAYS (itch <= mpn_mulmod_bnm1_itch (MAX_N, MAX_N, MAX_N));
175 1.1 mrg mpn_random2 (scratch-1, itch+2);
176 1.1 mrg s_before = scratch[-1];
177 1.1 mrg s_after = scratch[itch];
178 1.1 mrg
179 1.1 mrg mpn_mulmod_bnm1 ( pp, n, ap, an, bp, bn, scratch);
180 1.1 mrg ref_mulmod_bnm1 (refp, n, ap, an, bp, bn);
181 1.1 mrg if (pp[-1] != p_before || pp[rn] != p_after
182 1.1 mrg || scratch[-1] != s_before || scratch[itch] != s_after
183 1.1 mrg || mpn_cmp (refp, pp, rn) != 0)
184 1.1 mrg {
185 1.1 mrg printf ("ERROR in test %d, an = %d, bn = %d, n = %d\n",
186 1.1 mrg test, (int) an, (int) bn, (int) n);
187 1.1 mrg if (pp[-1] != p_before)
188 1.1 mrg {
189 1.1 mrg printf ("before pp:"); mpn_dump (pp -1, 1);
190 1.1 mrg printf ("keep: "); mpn_dump (&p_before, 1);
191 1.1 mrg }
192 1.1 mrg if (pp[rn] != p_after)
193 1.1 mrg {
194 1.1 mrg printf ("after pp:"); mpn_dump (pp + rn, 1);
195 1.1 mrg printf ("keep: "); mpn_dump (&p_after, 1);
196 1.1 mrg }
197 1.1 mrg if (scratch[-1] != s_before)
198 1.1 mrg {
199 1.1 mrg printf ("before scratch:"); mpn_dump (scratch-1, 1);
200 1.1 mrg printf ("keep: "); mpn_dump (&s_before, 1);
201 1.1 mrg }
202 1.1 mrg if (scratch[itch] != s_after)
203 1.1 mrg {
204 1.1 mrg printf ("after scratch:"); mpn_dump (scratch + itch, 1);
205 1.1 mrg printf ("keep: "); mpn_dump (&s_after, 1);
206 1.1 mrg }
207 1.1 mrg mpn_dump (ap, an);
208 1.1 mrg mpn_dump (bp, bn);
209 1.1 mrg mpn_dump (pp, rn);
210 1.1 mrg mpn_dump (refp, rn);
211 1.1 mrg
212 1.1 mrg abort();
213 1.1 mrg }
214 1.1 mrg }
215 1.1 mrg TMP_FREE;
216 1.1 mrg tests_end ();
217 1.1 mrg return 0;
218 1.1 mrg }
219