Viewing file: refmpz.c (6.8 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/* Reference mpz functions.
Copyright 1997, 1999-2002 Free Software Foundation, Inc.
This file is part of the GNU MP Library test suite.
The GNU MP Library test suite is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
The GNU MP Library test suite is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with the GNU MP Library test suite. If not, see https://www.gnu.org/licenses/. */
/* always do assertion checking */ #define WANT_ASSERT 1
#include <stdio.h> #include <stdlib.h> /* for free */ #include "gmp-impl.h" #include "longlong.h" #include "tests.h"
/* Change this to "#define TRACE(x) x" for some traces. */ #define TRACE(x)
/* FIXME: Shouldn't use plain mpz functions in a reference routine. */ void refmpz_combit (mpz_ptr r, unsigned long bit) { if (mpz_tstbit (r, bit)) mpz_clrbit (r, bit); else mpz_setbit (r, bit); }
unsigned long refmpz_hamdist (mpz_srcptr x, mpz_srcptr y) { mp_size_t xsize, ysize, tsize; mp_ptr xp, yp; unsigned long ret;
if ((SIZ(x) < 0 && SIZ(y) >= 0) || (SIZ(y) < 0 && SIZ(x) >= 0)) return ULONG_MAX;
xsize = ABSIZ(x); ysize = ABSIZ(y); tsize = MAX (xsize, ysize);
xp = refmpn_malloc_limbs (tsize); refmpn_zero (xp, tsize); refmpn_copy (xp, PTR(x), xsize);
yp = refmpn_malloc_limbs (tsize); refmpn_zero (yp, tsize); refmpn_copy (yp, PTR(y), ysize);
if (SIZ(x) < 0) refmpn_neg (xp, xp, tsize);
if (SIZ(x) < 0) refmpn_neg (yp, yp, tsize);
ret = refmpn_hamdist (xp, yp, tsize);
free (xp); free (yp); return ret; }
void refmpz_gcd (mpz_ptr g, mpz_srcptr a_orig, mpz_srcptr b_orig) { mp_bitcnt_t a_twos, b_twos, common_twos; mpz_t a; mpz_t b; mpz_init (a); mpz_init (b); mpz_abs (a, a_orig); mpz_abs (b, b_orig);
if (mpz_sgn (a) == 0) { mpz_set (g, b); return; } if (mpz_sgn (b) == 0) { mpz_set (g, a); return; } a_twos = mpz_scan1 (a, 0); mpz_tdiv_q_2exp (a, a, a_twos);
b_twos = mpz_scan1 (b, 0); mpz_tdiv_q_2exp (b, b, b_twos);
common_twos = MIN(a_twos, b_twos); for (;;) { int c; mp_bitcnt_t twos; c = mpz_cmp (a, b); if (c == 0) break; if (c < 0) mpz_swap (a, b); mpz_sub (a, a, b); twos = mpz_scan1 (a, 0); mpz_tdiv_q_2exp (a, a, twos); } mpz_mul_2exp (g, a, common_twos);
mpz_clear (a); mpz_clear (b); }
/* (0/b), with mpz b; is 1 if b=+/-1, 0 otherwise */ #define JACOBI_0Z(b) JACOBI_0LS (PTR(b)[0], SIZ(b))
/* (a/b) effect due to sign of b: mpz/mpz */ #define JACOBI_BSGN_ZZ_BIT1(a, b) JACOBI_BSGN_SS_BIT1 (SIZ(a), SIZ(b))
/* (a/b) effect due to sign of a: mpz/unsigned-mpz, b odd; is (-1/b) if a<0, or +1 if a>=0 */ #define JACOBI_ASGN_ZZU_BIT1(a, b) JACOBI_ASGN_SU_BIT1 (SIZ(a), PTR(b)[0])
int refmpz_kronecker (mpz_srcptr a_orig, mpz_srcptr b_orig) { unsigned long twos; mpz_t a, b; int result_bit1 = 0;
if (mpz_sgn (b_orig) == 0) return JACOBI_Z0 (a_orig); /* (a/0) */
if (mpz_sgn (a_orig) == 0) return JACOBI_0Z (b_orig); /* (0/b) */
if (mpz_even_p (a_orig) && mpz_even_p (b_orig)) return 0;
if (mpz_cmp_ui (b_orig, 1) == 0) return 1;
mpz_init_set (a, a_orig); mpz_init_set (b, b_orig);
if (mpz_sgn (b) < 0) { result_bit1 ^= JACOBI_BSGN_ZZ_BIT1 (a, b); mpz_neg (b, b); } if (mpz_even_p (b)) { twos = mpz_scan1 (b, 0L); mpz_tdiv_q_2exp (b, b, twos); result_bit1 ^= JACOBI_TWOS_U_BIT1 (twos, PTR(a)[0]); }
if (mpz_sgn (a) < 0) { result_bit1 ^= JACOBI_N1B_BIT1 (PTR(b)[0]); mpz_neg (a, a); } if (mpz_even_p (a)) { twos = mpz_scan1 (a, 0L); mpz_tdiv_q_2exp (a, a, twos); result_bit1 ^= JACOBI_TWOS_U_BIT1 (twos, PTR(b)[0]); }
for (;;) { ASSERT (mpz_odd_p (a)); ASSERT (mpz_odd_p (b)); ASSERT (mpz_sgn (a) > 0); ASSERT (mpz_sgn (b) > 0);
TRACE (printf ("top\n"); mpz_trace (" a", a); mpz_trace (" b", b));
if (mpz_cmp (a, b) < 0) { TRACE (printf ("swap\n")); mpz_swap (a, b); result_bit1 ^= JACOBI_RECIP_UU_BIT1 (PTR(a)[0], PTR(b)[0]); }
if (mpz_cmp_ui (b, 1) == 0) break;
mpz_sub (a, a, b); TRACE (printf ("sub\n"); mpz_trace (" a", a)); if (mpz_sgn (a) == 0) goto zero;
twos = mpz_scan1 (a, 0L); mpz_fdiv_q_2exp (a, a, twos); TRACE (printf ("twos %lu\n", twos); mpz_trace (" a", a)); result_bit1 ^= JACOBI_TWOS_U_BIT1 (twos, PTR(b)[0]); }
mpz_clear (a); mpz_clear (b); return JACOBI_BIT1_TO_PN (result_bit1);
zero: mpz_clear (a); mpz_clear (b); return 0; }
/* Same as mpz_kronecker, but ignoring factors of 2 on b */ int refmpz_jacobi (mpz_srcptr a, mpz_srcptr b) { ASSERT_ALWAYS (mpz_sgn (b) > 0); ASSERT_ALWAYS (mpz_odd_p (b));
return refmpz_kronecker (a, b); }
/* Legendre symbol via powm. p must be an odd prime. */ int refmpz_legendre (mpz_srcptr a, mpz_srcptr p) { int res;
mpz_t r; mpz_t e;
ASSERT_ALWAYS (mpz_sgn (p) > 0); ASSERT_ALWAYS (mpz_odd_p (p));
mpz_init (r); mpz_init (e);
mpz_fdiv_r (r, a, p);
mpz_set (e, p); mpz_sub_ui (e, e, 1); mpz_fdiv_q_2exp (e, e, 1); mpz_powm (r, r, e, p);
/* Normalize to a more or less symmetric range around zero */ if (mpz_cmp (r, e) > 0) mpz_sub (r, r, p);
ASSERT_ALWAYS (mpz_cmpabs_ui (r, 1) <= 0);
res = mpz_sgn (r);
mpz_clear (r); mpz_clear (e);
return res; }
int refmpz_kronecker_ui (mpz_srcptr a, unsigned long b) { mpz_t bz; int ret; mpz_init_set_ui (bz, b); ret = refmpz_kronecker (a, bz); mpz_clear (bz); return ret; }
int refmpz_kronecker_si (mpz_srcptr a, long b) { mpz_t bz; int ret; mpz_init_set_si (bz, b); ret = refmpz_kronecker (a, bz); mpz_clear (bz); return ret; }
int refmpz_ui_kronecker (unsigned long a, mpz_srcptr b) { mpz_t az; int ret; mpz_init_set_ui (az, a); ret = refmpz_kronecker (az, b); mpz_clear (az); return ret; }
int refmpz_si_kronecker (long a, mpz_srcptr b) { mpz_t az; int ret; mpz_init_set_si (az, a); ret = refmpz_kronecker (az, b); mpz_clear (az); return ret; }
void refmpz_pow_ui (mpz_ptr w, mpz_srcptr b, unsigned long e) { mpz_t s, t; unsigned long i;
mpz_init_set_ui (t, 1L); mpz_init_set (s, b);
if ((e & 1) != 0) mpz_mul (t, t, s);
for (i = 2; i <= e; i <<= 1) { mpz_mul (s, s, s); if ((i & e) != 0) mpz_mul (t, t, s); }
mpz_set (w, t);
mpz_clear (s); mpz_clear (t); }
|