t-sqrmod_bnm1.c revision 1.1.1.4 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.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.3 mrg the GNU MP Library test suite. If not, see https://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-impl.h"
27 1.1 mrg #include "tests.h"
28 1.1 mrg
29 1.1 mrg /* Sizes are up to 2^SIZE_LOG limbs */
30 1.1 mrg #ifndef SIZE_LOG
31 1.1 mrg #define SIZE_LOG 12
32 1.1 mrg #endif
33 1.1 mrg
34 1.1 mrg #ifndef COUNT
35 1.1 mrg #define COUNT 3000
36 1.1 mrg #endif
37 1.1 mrg
38 1.1 mrg #define MAX_N (1L << SIZE_LOG)
39 1.1 mrg #define MIN_N 1
40 1.1 mrg
41 1.1 mrg /*
42 1.1 mrg Reference function for squaring modulo B^rn-1.
43 1.1 mrg
44 1.1 mrg The result is expected to be ZERO if and only if one of the operand
45 1.1 mrg already is. Otherwise the class [0] Mod(B^rn-1) is represented by
46 1.1 mrg B^rn-1. This should not be a problem if sqrmod_bnm1 is used to
47 1.1 mrg combine results and obtain a natural number when one knows in
48 1.1 mrg advance that the final value is less than (B^rn-1).
49 1.1 mrg */
50 1.1 mrg
51 1.1 mrg static void
52 1.1 mrg ref_sqrmod_bnm1 (mp_ptr rp, mp_size_t rn, mp_srcptr ap, mp_size_t an)
53 1.1 mrg {
54 1.1 mrg mp_limb_t cy;
55 1.1 mrg
56 1.1 mrg ASSERT (0 < an && an <= rn);
57 1.1 mrg
58 1.1 mrg refmpn_mul (rp, ap, an, ap, an);
59 1.1 mrg an *= 2;
60 1.1 mrg if (an > rn) {
61 1.1 mrg cy = mpn_add (rp, rp, rn, rp + rn, an - rn);
62 1.1 mrg /* If cy == 1, then the value of rp is at most B^rn - 2, so there can
63 1.1 mrg * be no overflow when adding in the carry. */
64 1.1 mrg MPN_INCR_U (rp, rn, cy);
65 1.1 mrg }
66 1.1 mrg }
67 1.1 mrg
68 1.1 mrg /*
69 1.1 mrg Compare the result of the mpn_sqrmod_bnm1 function in the library
70 1.1 mrg with the reference function above.
71 1.1 mrg */
72 1.1 mrg
73 1.1 mrg int
74 1.1 mrg main (int argc, char **argv)
75 1.1 mrg {
76 1.1 mrg mp_ptr ap, refp, pp, scratch;
77 1.1 mrg int count = COUNT;
78 1.1 mrg int test;
79 1.1 mrg gmp_randstate_ptr rands;
80 1.1 mrg TMP_DECL;
81 1.1 mrg TMP_MARK;
82 1.1 mrg
83 1.1.1.4 mrg TESTS_REPS (count, argv, argc);
84 1.1 mrg
85 1.1 mrg tests_start ();
86 1.1 mrg rands = RANDS;
87 1.1 mrg
88 1.1 mrg ASSERT_ALWAYS (mpn_sqrmod_bnm1_next_size (MAX_N) == MAX_N);
89 1.1 mrg
90 1.1 mrg ap = TMP_ALLOC_LIMBS (MAX_N);
91 1.1 mrg refp = TMP_ALLOC_LIMBS (MAX_N * 4);
92 1.1 mrg pp = 1+TMP_ALLOC_LIMBS (MAX_N + 2);
93 1.1 mrg scratch
94 1.1 mrg = 1+TMP_ALLOC_LIMBS (mpn_sqrmod_bnm1_itch (MAX_N, MAX_N) + 2);
95 1.1 mrg
96 1.1 mrg for (test = 0; test < count; test++)
97 1.1 mrg {
98 1.1 mrg unsigned size_min;
99 1.1 mrg unsigned size_range;
100 1.1 mrg mp_size_t an,rn,n;
101 1.1 mrg mp_size_t itch;
102 1.1 mrg mp_limb_t p_before, p_after, s_before, s_after;
103 1.1 mrg
104 1.1 mrg for (size_min = 1; (1L << size_min) < MIN_N; size_min++)
105 1.1 mrg ;
106 1.1 mrg
107 1.1 mrg /* We generate an in the MIN_N <= n <= (1 << size_range). */
108 1.1 mrg size_range = size_min
109 1.1 mrg + gmp_urandomm_ui (rands, SIZE_LOG + 1 - size_min);
110 1.1 mrg
111 1.1 mrg n = MIN_N
112 1.1 mrg + gmp_urandomm_ui (rands, (1L << size_range) + 1 - MIN_N);
113 1.1 mrg n = mpn_sqrmod_bnm1_next_size (n);
114 1.1 mrg
115 1.1 mrg if (n == 1)
116 1.1 mrg an = 1;
117 1.1 mrg else
118 1.1 mrg an = ((n+1) >> 1) + gmp_urandomm_ui (rands, (n+1) >> 1);
119 1.1 mrg
120 1.1 mrg mpn_random2 (ap, an);
121 1.1 mrg
122 1.1 mrg /* Sometime trigger the borderline conditions
123 1.1 mrg A = -1,0,+1 Mod(B^{n/2}+1).
124 1.1 mrg This only makes sense if there is at least a split, i.e. n is even. */
125 1.1 mrg if ((test & 0x1f) == 1 && (n & 1) == 0) {
126 1.1 mrg mp_size_t x;
127 1.1 mrg MPN_COPY (ap, ap + (n >> 1), an - (n >> 1));
128 1.1 mrg MPN_ZERO (ap + an - (n >> 1) , n - an);
129 1.1 mrg x = (n == an) ? 0 : gmp_urandomm_ui (rands, n - an);
130 1.1 mrg ap[x] += gmp_urandomm_ui (rands, 3) - 1;
131 1.1 mrg }
132 1.1 mrg rn = MIN(n, 2*an);
133 1.1 mrg mpn_random2 (pp-1, rn + 2);
134 1.1 mrg p_before = pp[-1];
135 1.1 mrg p_after = pp[rn];
136 1.1 mrg
137 1.1 mrg itch = mpn_sqrmod_bnm1_itch (n, an);
138 1.1 mrg ASSERT_ALWAYS (itch <= mpn_sqrmod_bnm1_itch (MAX_N, MAX_N));
139 1.1 mrg mpn_random2 (scratch-1, itch+2);
140 1.1 mrg s_before = scratch[-1];
141 1.1 mrg s_after = scratch[itch];
142 1.1 mrg
143 1.1 mrg mpn_sqrmod_bnm1 ( pp, n, ap, an, scratch);
144 1.1 mrg ref_sqrmod_bnm1 (refp, n, ap, an);
145 1.1 mrg if (pp[-1] != p_before || pp[rn] != p_after
146 1.1 mrg || scratch[-1] != s_before || scratch[itch] != s_after
147 1.1 mrg || mpn_cmp (refp, pp, rn) != 0)
148 1.1 mrg {
149 1.1 mrg printf ("ERROR in test %d, an = %d, n = %d\n",
150 1.1 mrg test, (int) an, (int) n);
151 1.1 mrg if (pp[-1] != p_before)
152 1.1 mrg {
153 1.1 mrg printf ("before pp:"); mpn_dump (pp -1, 1);
154 1.1 mrg printf ("keep: "); mpn_dump (&p_before, 1);
155 1.1 mrg }
156 1.1 mrg if (pp[rn] != p_after)
157 1.1 mrg {
158 1.1 mrg printf ("after pp:"); mpn_dump (pp + rn, 1);
159 1.1 mrg printf ("keep: "); mpn_dump (&p_after, 1);
160 1.1 mrg }
161 1.1 mrg if (scratch[-1] != s_before)
162 1.1 mrg {
163 1.1 mrg printf ("before scratch:"); mpn_dump (scratch-1, 1);
164 1.1 mrg printf ("keep: "); mpn_dump (&s_before, 1);
165 1.1 mrg }
166 1.1 mrg if (scratch[itch] != s_after)
167 1.1 mrg {
168 1.1 mrg printf ("after scratch:"); mpn_dump (scratch + itch, 1);
169 1.1 mrg printf ("keep: "); mpn_dump (&s_after, 1);
170 1.1 mrg }
171 1.1 mrg mpn_dump (ap, an);
172 1.1 mrg mpn_dump (pp, rn);
173 1.1 mrg mpn_dump (refp, rn);
174 1.1 mrg
175 1.1 mrg abort();
176 1.1 mrg }
177 1.1 mrg }
178 1.1 mrg TMP_FREE;
179 1.1 mrg tests_end ();
180 1.1 mrg return 0;
181 1.1 mrg }
182