1 /* Reference mpz functions.
2
3 Copyright 1997, 1999-2002 Free Software Foundation, Inc.
4
5 This file is part of the GNU MP Library test suite.
6
7 The GNU MP Library test suite is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 3 of the License,
10 or (at your option) any later version.
11
12 The GNU MP Library test suite is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15 Public License for more details.
16
17 You should have received a copy of the GNU General Public License along with
18 the GNU MP Library test suite. If not, see https://www.gnu.org/licenses/. */
19
20 /* always do assertion checking */
21 #define WANT_ASSERT 1
22
23 #include <stdio.h>
24 #include <stdlib.h> /* for free */
25 #include "gmp-impl.h"
26 #include "longlong.h"
27 #include "tests.h"
28
29
30 /* Change this to "#define TRACE(x) x" for some traces. */
31 #define TRACE(x)
32
33
34 /* FIXME: Shouldn't use plain mpz functions in a reference routine. */
35 void
refmpz_combit(mpz_ptr r,unsigned long bit)36 refmpz_combit (mpz_ptr r, unsigned long bit)
37 {
38 if (mpz_tstbit (r, bit))
39 mpz_clrbit (r, bit);
40 else
41 mpz_setbit (r, bit);
42 }
43
44
45 unsigned long
refmpz_hamdist(mpz_srcptr x,mpz_srcptr y)46 refmpz_hamdist (mpz_srcptr x, mpz_srcptr y)
47 {
48 mp_size_t xsize, ysize, tsize;
49 mp_ptr xp, yp;
50 unsigned long ret;
51
52 if ((SIZ(x) < 0 && SIZ(y) >= 0)
53 || (SIZ(y) < 0 && SIZ(x) >= 0))
54 return ULONG_MAX;
55
56 xsize = ABSIZ(x);
57 ysize = ABSIZ(y);
58 tsize = MAX (xsize, ysize);
59
60 xp = refmpn_malloc_limbs (tsize);
61 refmpn_zero (xp, tsize);
62 refmpn_copy (xp, PTR(x), xsize);
63
64 yp = refmpn_malloc_limbs (tsize);
65 refmpn_zero (yp, tsize);
66 refmpn_copy (yp, PTR(y), ysize);
67
68 if (SIZ(x) < 0)
69 refmpn_neg (xp, xp, tsize);
70
71 if (SIZ(x) < 0)
72 refmpn_neg (yp, yp, tsize);
73
74 ret = refmpn_hamdist (xp, yp, tsize);
75
76 free (xp);
77 free (yp);
78 return ret;
79 }
80
81 void
refmpz_gcd(mpz_ptr g,mpz_srcptr a_orig,mpz_srcptr b_orig)82 refmpz_gcd (mpz_ptr g, mpz_srcptr a_orig, mpz_srcptr b_orig)
83 {
84 mp_bitcnt_t a_twos, b_twos, common_twos;
85 mpz_t a;
86 mpz_t b;
87 mpz_init (a);
88 mpz_init (b);
89 mpz_abs (a, a_orig);
90 mpz_abs (b, b_orig);
91
92 if (mpz_sgn (a) == 0)
93 {
94 mpz_set (g, b);
95 return;
96 }
97 if (mpz_sgn (b) == 0)
98 {
99 mpz_set (g, a);
100 return;
101 }
102 a_twos = mpz_scan1 (a, 0);
103 mpz_tdiv_q_2exp (a, a, a_twos);
104
105 b_twos = mpz_scan1 (b, 0);
106 mpz_tdiv_q_2exp (b, b, b_twos);
107
108 common_twos = MIN(a_twos, b_twos);
109 for (;;)
110 {
111 int c;
112 mp_bitcnt_t twos;
113 c = mpz_cmp (a, b);
114 if (c == 0)
115 break;
116 if (c < 0)
117 mpz_swap (a, b);
118 mpz_sub (a, a, b);
119 twos = mpz_scan1 (a, 0);
120 mpz_tdiv_q_2exp (a, a, twos);
121 }
122 mpz_mul_2exp (g, a, common_twos);
123
124 mpz_clear (a);
125 mpz_clear (b);
126 }
127
128 /* (0/b), with mpz b; is 1 if b=+/-1, 0 otherwise */
129 #define JACOBI_0Z(b) JACOBI_0LS (PTR(b)[0], SIZ(b))
130
131 /* (a/b) effect due to sign of b: mpz/mpz */
132 #define JACOBI_BSGN_ZZ_BIT1(a, b) JACOBI_BSGN_SS_BIT1 (SIZ(a), SIZ(b))
133
134 /* (a/b) effect due to sign of a: mpz/unsigned-mpz, b odd;
135 is (-1/b) if a<0, or +1 if a>=0 */
136 #define JACOBI_ASGN_ZZU_BIT1(a, b) JACOBI_ASGN_SU_BIT1 (SIZ(a), PTR(b)[0])
137
138 int
refmpz_kronecker(mpz_srcptr a_orig,mpz_srcptr b_orig)139 refmpz_kronecker (mpz_srcptr a_orig, mpz_srcptr b_orig)
140 {
141 unsigned long twos;
142 mpz_t a, b;
143 int result_bit1 = 0;
144
145 if (mpz_sgn (b_orig) == 0)
146 return JACOBI_Z0 (a_orig); /* (a/0) */
147
148 if (mpz_sgn (a_orig) == 0)
149 return JACOBI_0Z (b_orig); /* (0/b) */
150
151 if (mpz_even_p (a_orig) && mpz_even_p (b_orig))
152 return 0;
153
154 if (mpz_cmp_ui (b_orig, 1) == 0)
155 return 1;
156
157 mpz_init_set (a, a_orig);
158 mpz_init_set (b, b_orig);
159
160 if (mpz_sgn (b) < 0)
161 {
162 result_bit1 ^= JACOBI_BSGN_ZZ_BIT1 (a, b);
163 mpz_neg (b, b);
164 }
165 if (mpz_even_p (b))
166 {
167 twos = mpz_scan1 (b, 0L);
168 mpz_tdiv_q_2exp (b, b, twos);
169 result_bit1 ^= JACOBI_TWOS_U_BIT1 (twos, PTR(a)[0]);
170 }
171
172 if (mpz_sgn (a) < 0)
173 {
174 result_bit1 ^= JACOBI_N1B_BIT1 (PTR(b)[0]);
175 mpz_neg (a, a);
176 }
177 if (mpz_even_p (a))
178 {
179 twos = mpz_scan1 (a, 0L);
180 mpz_tdiv_q_2exp (a, a, twos);
181 result_bit1 ^= JACOBI_TWOS_U_BIT1 (twos, PTR(b)[0]);
182 }
183
184 for (;;)
185 {
186 ASSERT (mpz_odd_p (a));
187 ASSERT (mpz_odd_p (b));
188 ASSERT (mpz_sgn (a) > 0);
189 ASSERT (mpz_sgn (b) > 0);
190
191 TRACE (printf ("top\n");
192 mpz_trace (" a", a);
193 mpz_trace (" b", b));
194
195 if (mpz_cmp (a, b) < 0)
196 {
197 TRACE (printf ("swap\n"));
198 mpz_swap (a, b);
199 result_bit1 ^= JACOBI_RECIP_UU_BIT1 (PTR(a)[0], PTR(b)[0]);
200 }
201
202 if (mpz_cmp_ui (b, 1) == 0)
203 break;
204
205 mpz_sub (a, a, b);
206 TRACE (printf ("sub\n");
207 mpz_trace (" a", a));
208 if (mpz_sgn (a) == 0)
209 goto zero;
210
211 twos = mpz_scan1 (a, 0L);
212 mpz_fdiv_q_2exp (a, a, twos);
213 TRACE (printf ("twos %lu\n", twos);
214 mpz_trace (" a", a));
215 result_bit1 ^= JACOBI_TWOS_U_BIT1 (twos, PTR(b)[0]);
216 }
217
218 mpz_clear (a);
219 mpz_clear (b);
220 return JACOBI_BIT1_TO_PN (result_bit1);
221
222 zero:
223 mpz_clear (a);
224 mpz_clear (b);
225 return 0;
226 }
227
228 /* Same as mpz_kronecker, but ignoring factors of 2 on b */
229 int
refmpz_jacobi(mpz_srcptr a,mpz_srcptr b)230 refmpz_jacobi (mpz_srcptr a, mpz_srcptr b)
231 {
232 ASSERT_ALWAYS (mpz_sgn (b) > 0);
233 ASSERT_ALWAYS (mpz_odd_p (b));
234
235 return refmpz_kronecker (a, b);
236 }
237
238 /* Legendre symbol via powm. p must be an odd prime. */
239 int
refmpz_legendre(mpz_srcptr a,mpz_srcptr p)240 refmpz_legendre (mpz_srcptr a, mpz_srcptr p)
241 {
242 int res;
243
244 mpz_t r;
245 mpz_t e;
246
247 ASSERT_ALWAYS (mpz_sgn (p) > 0);
248 ASSERT_ALWAYS (mpz_odd_p (p));
249
250 mpz_init (r);
251 mpz_init (e);
252
253 mpz_fdiv_r (r, a, p);
254
255 mpz_set (e, p);
256 mpz_sub_ui (e, e, 1);
257 mpz_fdiv_q_2exp (e, e, 1);
258 mpz_powm (r, r, e, p);
259
260 /* Normalize to a more or less symmetric range around zero */
261 if (mpz_cmp (r, e) > 0)
262 mpz_sub (r, r, p);
263
264 ASSERT_ALWAYS (mpz_cmpabs_ui (r, 1) <= 0);
265
266 res = mpz_sgn (r);
267
268 mpz_clear (r);
269 mpz_clear (e);
270
271 return res;
272 }
273
274
275 int
refmpz_kronecker_ui(mpz_srcptr a,unsigned long b)276 refmpz_kronecker_ui (mpz_srcptr a, unsigned long b)
277 {
278 mpz_t bz;
279 int ret;
280 mpz_init_set_ui (bz, b);
281 ret = refmpz_kronecker (a, bz);
282 mpz_clear (bz);
283 return ret;
284 }
285
286 int
refmpz_kronecker_si(mpz_srcptr a,long b)287 refmpz_kronecker_si (mpz_srcptr a, long b)
288 {
289 mpz_t bz;
290 int ret;
291 mpz_init_set_si (bz, b);
292 ret = refmpz_kronecker (a, bz);
293 mpz_clear (bz);
294 return ret;
295 }
296
297 int
refmpz_ui_kronecker(unsigned long a,mpz_srcptr b)298 refmpz_ui_kronecker (unsigned long a, mpz_srcptr b)
299 {
300 mpz_t az;
301 int ret;
302 mpz_init_set_ui (az, a);
303 ret = refmpz_kronecker (az, b);
304 mpz_clear (az);
305 return ret;
306 }
307
308 int
refmpz_si_kronecker(long a,mpz_srcptr b)309 refmpz_si_kronecker (long a, mpz_srcptr b)
310 {
311 mpz_t az;
312 int ret;
313 mpz_init_set_si (az, a);
314 ret = refmpz_kronecker (az, b);
315 mpz_clear (az);
316 return ret;
317 }
318
319
320 void
refmpz_pow_ui(mpz_ptr w,mpz_srcptr b,unsigned long e)321 refmpz_pow_ui (mpz_ptr w, mpz_srcptr b, unsigned long e)
322 {
323 mpz_t s, t;
324 unsigned long i;
325
326 mpz_init_set_ui (t, 1L);
327 mpz_init_set (s, b);
328
329 if ((e & 1) != 0)
330 mpz_mul (t, t, s);
331
332 for (i = 2; i <= e; i <<= 1)
333 {
334 mpz_mul (s, s, s);
335 if ((i & e) != 0)
336 mpz_mul (t, t, s);
337 }
338
339 mpz_set (w, t);
340
341 mpz_clear (s);
342 mpz_clear (t);
343 }
344