Austin Schuh | dace2a6 | 2020-08-18 10:56:48 -0700 | [diff] [blame] | 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 | } |