t-sqrmod_bnm1.c revision 1.1 1 1.1 mrg /* Test for sqrmod_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 mrg This file is part of the GNU MP Library.
8 1.1 mrg
9 1.1 mrg The GNU MP Library is free software; you can redistribute it and/or modify
10 1.1 mrg it under the terms of the GNU Lesser General Public License as published by
11 1.1 mrg the Free Software Foundation; either version 3 of the License, or (at your
12 1.1 mrg option) any later version.
13 1.1 mrg
14 1.1 mrg The GNU MP Library is distributed in the hope that it will be useful, but
15 1.1 mrg WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 1.1 mrg or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17 1.1 mrg License for more details.
18 1.1 mrg
19 1.1 mrg You should have received a copy of the GNU Lesser General Public License
20 1.1 mrg along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */
21 1.1 mrg
22 1.1 mrg
23 1.1 mrg #include "gmp.h"
24 1.1 mrg #include "gmp-impl.h"
25 1.1 mrg #include "tests.h"
26 1.1 mrg
27 1.1 mrg #include <stdlib.h>
28 1.1 mrg #include <stdio.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 12
33 1.1 mrg #endif
34 1.1 mrg
35 1.1 mrg #ifndef COUNT
36 1.1 mrg #define COUNT 3000
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 squaring 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 sqrmod_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_sqrmod_bnm1 (mp_ptr rp, mp_size_t rn, mp_srcptr ap, mp_size_t an)
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
59 1.1 mrg refmpn_mul (rp, ap, an, ap, an);
60 1.1 mrg an *= 2;
61 1.1 mrg if (an > rn) {
62 1.1 mrg cy = mpn_add (rp, rp, rn, rp + rn, an - rn);
63 1.1 mrg /* If cy == 1, then the value of rp is at most B^rn - 2, so there can
64 1.1 mrg * be no overflow when adding in the carry. */
65 1.1 mrg MPN_INCR_U (rp, rn, cy);
66 1.1 mrg }
67 1.1 mrg }
68 1.1 mrg
69 1.1 mrg /*
70 1.1 mrg Compare the result of the mpn_sqrmod_bnm1 function in the library
71 1.1 mrg with the reference function above.
72 1.1 mrg */
73 1.1 mrg
74 1.1 mrg int
75 1.1 mrg main (int argc, char **argv)
76 1.1 mrg {
77 1.1 mrg mp_ptr ap, refp, pp, scratch;
78 1.1 mrg int count = COUNT;
79 1.1 mrg int test;
80 1.1 mrg gmp_randstate_ptr rands;
81 1.1 mrg TMP_DECL;
82 1.1 mrg TMP_MARK;
83 1.1 mrg
84 1.1 mrg if (argc > 1)
85 1.1 mrg {
86 1.1 mrg char *end;
87 1.1 mrg count = strtol (argv[1], &end, 0);
88 1.1 mrg if (*end || count <= 0)
89 1.1 mrg {
90 1.1 mrg fprintf (stderr, "Invalid test count: %s.\n", argv[1]);
91 1.1 mrg return 1;
92 1.1 mrg }
93 1.1 mrg }
94 1.1 mrg
95 1.1 mrg tests_start ();
96 1.1 mrg rands = RANDS;
97 1.1 mrg
98 1.1 mrg ASSERT_ALWAYS (mpn_sqrmod_bnm1_next_size (MAX_N) == MAX_N);
99 1.1 mrg
100 1.1 mrg ap = TMP_ALLOC_LIMBS (MAX_N);
101 1.1 mrg refp = TMP_ALLOC_LIMBS (MAX_N * 4);
102 1.1 mrg pp = 1+TMP_ALLOC_LIMBS (MAX_N + 2);
103 1.1 mrg scratch
104 1.1 mrg = 1+TMP_ALLOC_LIMBS (mpn_sqrmod_bnm1_itch (MAX_N, MAX_N) + 2);
105 1.1 mrg
106 1.1 mrg for (test = 0; test < count; test++)
107 1.1 mrg {
108 1.1 mrg unsigned size_min;
109 1.1 mrg unsigned size_range;
110 1.1 mrg mp_size_t an,rn,n;
111 1.1 mrg mp_size_t itch;
112 1.1 mrg mp_limb_t p_before, p_after, s_before, s_after;
113 1.1 mrg
114 1.1 mrg for (size_min = 1; (1L << size_min) < MIN_N; size_min++)
115 1.1 mrg ;
116 1.1 mrg
117 1.1 mrg /* We generate an in the MIN_N <= n <= (1 << size_range). */
118 1.1 mrg size_range = size_min
119 1.1 mrg + gmp_urandomm_ui (rands, SIZE_LOG + 1 - size_min);
120 1.1 mrg
121 1.1 mrg n = MIN_N
122 1.1 mrg + gmp_urandomm_ui (rands, (1L << size_range) + 1 - MIN_N);
123 1.1 mrg n = mpn_sqrmod_bnm1_next_size (n);
124 1.1 mrg
125 1.1 mrg if (n == 1)
126 1.1 mrg an = 1;
127 1.1 mrg else
128 1.1 mrg an = ((n+1) >> 1) + gmp_urandomm_ui (rands, (n+1) >> 1);
129 1.1 mrg
130 1.1 mrg mpn_random2 (ap, an);
131 1.1 mrg
132 1.1 mrg /* Sometime trigger the borderline conditions
133 1.1 mrg A = -1,0,+1 Mod(B^{n/2}+1).
134 1.1 mrg This only makes sense if there is at least a split, i.e. n is even. */
135 1.1 mrg if ((test & 0x1f) == 1 && (n & 1) == 0) {
136 1.1 mrg mp_size_t x;
137 1.1 mrg MPN_COPY (ap, ap + (n >> 1), an - (n >> 1));
138 1.1 mrg MPN_ZERO (ap + an - (n >> 1) , n - an);
139 1.1 mrg x = (n == an) ? 0 : gmp_urandomm_ui (rands, n - an);
140 1.1 mrg ap[x] += gmp_urandomm_ui (rands, 3) - 1;
141 1.1 mrg }
142 1.1 mrg rn = MIN(n, 2*an);
143 1.1 mrg mpn_random2 (pp-1, rn + 2);
144 1.1 mrg p_before = pp[-1];
145 1.1 mrg p_after = pp[rn];
146 1.1 mrg
147 1.1 mrg itch = mpn_sqrmod_bnm1_itch (n, an);
148 1.1 mrg ASSERT_ALWAYS (itch <= mpn_sqrmod_bnm1_itch (MAX_N, MAX_N));
149 1.1 mrg mpn_random2 (scratch-1, itch+2);
150 1.1 mrg s_before = scratch[-1];
151 1.1 mrg s_after = scratch[itch];
152 1.1 mrg
153 1.1 mrg mpn_sqrmod_bnm1 ( pp, n, ap, an, scratch);
154 1.1 mrg ref_sqrmod_bnm1 (refp, n, ap, an);
155 1.1 mrg if (pp[-1] != p_before || pp[rn] != p_after
156 1.1 mrg || scratch[-1] != s_before || scratch[itch] != s_after
157 1.1 mrg || mpn_cmp (refp, pp, rn) != 0)
158 1.1 mrg {
159 1.1 mrg printf ("ERROR in test %d, an = %d, n = %d\n",
160 1.1 mrg test, (int) an, (int) n);
161 1.1 mrg if (pp[-1] != p_before)
162 1.1 mrg {
163 1.1 mrg printf ("before pp:"); mpn_dump (pp -1, 1);
164 1.1 mrg printf ("keep: "); mpn_dump (&p_before, 1);
165 1.1 mrg }
166 1.1 mrg if (pp[rn] != p_after)
167 1.1 mrg {
168 1.1 mrg printf ("after pp:"); mpn_dump (pp + rn, 1);
169 1.1 mrg printf ("keep: "); mpn_dump (&p_after, 1);
170 1.1 mrg }
171 1.1 mrg if (scratch[-1] != s_before)
172 1.1 mrg {
173 1.1 mrg printf ("before scratch:"); mpn_dump (scratch-1, 1);
174 1.1 mrg printf ("keep: "); mpn_dump (&s_before, 1);
175 1.1 mrg }
176 1.1 mrg if (scratch[itch] != s_after)
177 1.1 mrg {
178 1.1 mrg printf ("after scratch:"); mpn_dump (scratch + itch, 1);
179 1.1 mrg printf ("keep: "); mpn_dump (&s_after, 1);
180 1.1 mrg }
181 1.1 mrg mpn_dump (ap, an);
182 1.1 mrg mpn_dump (pp, rn);
183 1.1 mrg mpn_dump (refp, rn);
184 1.1 mrg
185 1.1 mrg abort();
186 1.1 mrg }
187 1.1 mrg }
188 1.1 mrg TMP_FREE;
189 1.1 mrg tests_end ();
190 1.1 mrg return 0;
191 1.1 mrg }
192