Blame tests/refmpz.c

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