Blame mpn/generic/jacobi_2.c

Packit 5c3484
/* jacobi_2.c
Packit 5c3484
Packit 5c3484
   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
Packit 5c3484
   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
Packit 5c3484
   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
Packit 5c3484
Packit 5c3484
Copyright 1996, 1998, 2000-2004, 2008, 2010 Free Software Foundation, Inc.
Packit 5c3484
Packit 5c3484
This file is part of the GNU MP Library.
Packit 5c3484
Packit 5c3484
The GNU MP Library is free software; you can redistribute it and/or modify
Packit 5c3484
it under the terms of either:
Packit 5c3484
Packit 5c3484
  * the GNU Lesser General Public License as published by the Free
Packit 5c3484
    Software Foundation; either version 3 of the License, or (at your
Packit 5c3484
    option) any later version.
Packit 5c3484
Packit 5c3484
or
Packit 5c3484
Packit 5c3484
  * the GNU General Public License as published by the Free Software
Packit 5c3484
    Foundation; either version 2 of the License, or (at your option) any
Packit 5c3484
    later version.
Packit 5c3484
Packit 5c3484
or both in parallel, as here.
Packit 5c3484
Packit 5c3484
The GNU MP Library is distributed in the hope that it will be useful, but
Packit 5c3484
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
Packit 5c3484
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
Packit 5c3484
for more details.
Packit 5c3484
Packit 5c3484
You should have received copies of the GNU General Public License and the
Packit 5c3484
GNU Lesser General Public License along with the GNU MP Library.  If not,
Packit 5c3484
see https://www.gnu.org/licenses/.  */
Packit 5c3484
Packit 5c3484
#include "gmp.h"
Packit 5c3484
#include "gmp-impl.h"
Packit 5c3484
#include "longlong.h"
Packit 5c3484
Packit 5c3484
#ifndef JACOBI_2_METHOD
Packit 5c3484
#define JACOBI_2_METHOD 2
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484
/* Computes (a / b) where b is odd, and a and b are otherwise arbitrary
Packit 5c3484
   two-limb numbers. */
Packit 5c3484
#if JACOBI_2_METHOD == 1
Packit 5c3484
int
Packit 5c3484
mpn_jacobi_2 (mp_srcptr ap, mp_srcptr bp, unsigned bit)
Packit 5c3484
{
Packit 5c3484
  mp_limb_t ah, al, bh, bl;
Packit 5c3484
  int c;
Packit 5c3484
Packit 5c3484
  al = ap[0];
Packit 5c3484
  ah = ap[1];
Packit 5c3484
  bl = bp[0];
Packit 5c3484
  bh = bp[1];
Packit 5c3484
Packit 5c3484
  ASSERT (bl & 1);
Packit 5c3484
Packit 5c3484
  bl = ((bh << (GMP_NUMB_BITS - 1)) & GMP_NUMB_MASK) | (bl >> 1);
Packit 5c3484
  bh >>= 1;
Packit 5c3484
Packit 5c3484
  if ( (bh | bl) == 0)
Packit 5c3484
    return 1 - 2*(bit & 1);
Packit 5c3484
Packit 5c3484
  if ( (ah | al) == 0)
Packit 5c3484
    return 0;
Packit 5c3484
Packit 5c3484
  if (al == 0)
Packit 5c3484
    {
Packit 5c3484
      al = ah;
Packit 5c3484
      ah = 0;
Packit 5c3484
      bit ^= GMP_NUMB_BITS & (bl ^ (bl >> 1));
Packit 5c3484
    }
Packit 5c3484
  count_trailing_zeros (c, al);
Packit 5c3484
  bit ^= c & (bl ^ (bl >> 1));
Packit 5c3484
Packit 5c3484
  c++;
Packit 5c3484
  if (UNLIKELY (c == GMP_NUMB_BITS))
Packit 5c3484
    {
Packit 5c3484
      al = ah;
Packit 5c3484
      ah = 0;
Packit 5c3484
    }
Packit 5c3484
  else
Packit 5c3484
    {
Packit 5c3484
      al = ((ah << (GMP_NUMB_BITS - c)) & GMP_NUMB_MASK) | (al >> c);
Packit 5c3484
      ah >>= c;
Packit 5c3484
    }
Packit 5c3484
  while ( (ah | bh) > 0)
Packit 5c3484
    {
Packit 5c3484
      mp_limb_t th, tl;
Packit 5c3484
      mp_limb_t bgta;
Packit 5c3484
Packit 5c3484
      sub_ddmmss (th, tl, ah, al, bh, bl);
Packit 5c3484
      if ( (tl | th) == 0)
Packit 5c3484
	return 0;
Packit 5c3484
Packit 5c3484
      bgta = LIMB_HIGHBIT_TO_MASK (th);
Packit 5c3484
Packit 5c3484
      /* If b > a, invoke reciprocity */
Packit 5c3484
      bit ^= (bgta & al & bl);
Packit 5c3484
Packit 5c3484
      /* b <-- min (a, b) */
Packit 5c3484
      add_ssaaaa (bh, bl, bh, bl, th & bgta, tl & bgta);
Packit 5c3484
Packit 5c3484
      if ( (bh | bl) == 0)
Packit 5c3484
	return 1 - 2*(bit & 1);
Packit 5c3484
Packit 5c3484
      /* a <-- |a - b| */
Packit 5c3484
      al = (bgta ^ tl) - bgta;
Packit 5c3484
      ah = (bgta ^ th);
Packit 5c3484
Packit 5c3484
      if (UNLIKELY (al == 0))
Packit 5c3484
	{
Packit 5c3484
	  /* If b > a, al == 0 implies that we have a carry to
Packit 5c3484
	     propagate. */
Packit 5c3484
	  al = ah - bgta;
Packit 5c3484
	  ah = 0;
Packit 5c3484
	  bit ^= GMP_NUMB_BITS & (bl ^ (bl >> 1));
Packit 5c3484
	}
Packit 5c3484
      count_trailing_zeros (c, al);
Packit 5c3484
      c++;
Packit 5c3484
      bit ^= c & (bl ^ (bl >> 1));
Packit 5c3484
Packit 5c3484
      if (UNLIKELY (c == GMP_NUMB_BITS))
Packit 5c3484
	{
Packit 5c3484
	  al = ah;
Packit 5c3484
	  ah = 0;
Packit 5c3484
	}
Packit 5c3484
      else
Packit 5c3484
	{
Packit 5c3484
	  al = ((ah << (GMP_NUMB_BITS - c)) & GMP_NUMB_MASK) | (al >> c);
Packit 5c3484
	  ah >>= c;
Packit 5c3484
	}
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  ASSERT (bl > 0);
Packit 5c3484
Packit 5c3484
  while ( (al | bl) & GMP_LIMB_HIGHBIT)
Packit 5c3484
    {
Packit 5c3484
      /* Need an extra comparison to get the mask. */
Packit 5c3484
      mp_limb_t t = al - bl;
Packit 5c3484
      mp_limb_t bgta = - (bl > al);
Packit 5c3484
Packit 5c3484
      if (t == 0)
Packit 5c3484
	return 0;
Packit 5c3484
Packit 5c3484
      /* If b > a, invoke reciprocity */
Packit 5c3484
      bit ^= (bgta & al & bl);
Packit 5c3484
Packit 5c3484
      /* b <-- min (a, b) */
Packit 5c3484
      bl += (bgta & t);
Packit 5c3484
Packit 5c3484
      /* a <-- |a - b| */
Packit 5c3484
      al = (t ^ bgta) - bgta;
Packit 5c3484
Packit 5c3484
      /* Number of trailing zeros is the same no matter if we look at
Packit 5c3484
       * t or a, but using t gives more parallelism. */
Packit 5c3484
      count_trailing_zeros (c, t);
Packit 5c3484
      c ++;
Packit 5c3484
      /* (2/b) = -1 if b = 3 or 5 mod 8 */
Packit 5c3484
      bit ^= c & (bl ^ (bl >> 1));
Packit 5c3484
Packit 5c3484
      if (UNLIKELY (c == GMP_NUMB_BITS))
Packit 5c3484
	return 1 - 2*(bit & 1);
Packit 5c3484
Packit 5c3484
      al >>= c;
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  /* Here we have a little impedance mismatch. Better to inline it? */
Packit 5c3484
  return mpn_jacobi_base (2*al+1, 2*bl+1, bit << 1);
Packit 5c3484
}
Packit 5c3484
#elif JACOBI_2_METHOD == 2
Packit 5c3484
int
Packit 5c3484
mpn_jacobi_2 (mp_srcptr ap, mp_srcptr bp, unsigned bit)
Packit 5c3484
{
Packit 5c3484
  mp_limb_t ah, al, bh, bl;
Packit 5c3484
  int c;
Packit 5c3484
Packit 5c3484
  al = ap[0];
Packit 5c3484
  ah = ap[1];
Packit 5c3484
  bl = bp[0];
Packit 5c3484
  bh = bp[1];
Packit 5c3484
Packit 5c3484
  ASSERT (bl & 1);
Packit 5c3484
Packit 5c3484
  /* Use bit 1. */
Packit 5c3484
  bit <<= 1;
Packit 5c3484
Packit 5c3484
  if (bh == 0 && bl == 1)
Packit 5c3484
    /* (a|1) = 1 */
Packit 5c3484
    return 1 - (bit & 2);
Packit 5c3484
Packit 5c3484
  if (al == 0)
Packit 5c3484
    {
Packit 5c3484
      if (ah == 0)
Packit 5c3484
	/* (0|b) = 0, b > 1 */
Packit 5c3484
	return 0;
Packit 5c3484
Packit 5c3484
      count_trailing_zeros (c, ah);
Packit 5c3484
      bit ^= ((GMP_NUMB_BITS + c) << 1) & (bl ^ (bl >> 1));
Packit 5c3484
Packit 5c3484
      al = bl;
Packit 5c3484
      bl = ah >> c;
Packit 5c3484
Packit 5c3484
      if (bl == 1)
Packit 5c3484
	/* (1|b) = 1 */
Packit 5c3484
	return 1 - (bit & 2);
Packit 5c3484
Packit 5c3484
      ah = bh;
Packit 5c3484
Packit 5c3484
      bit ^= al & bl;
Packit 5c3484
Packit 5c3484
      goto b_reduced;
Packit 5c3484
    }
Packit 5c3484
  if ( (al & 1) == 0)
Packit 5c3484
    {
Packit 5c3484
      count_trailing_zeros (c, al);
Packit 5c3484
Packit 5c3484
      al = ((ah << (GMP_NUMB_BITS - c)) & GMP_NUMB_MASK) | (al >> c);
Packit 5c3484
      ah >>= c;
Packit 5c3484
      bit ^= (c << 1) & (bl ^ (bl >> 1));
Packit 5c3484
    }
Packit 5c3484
  if (ah == 0)
Packit 5c3484
    {
Packit 5c3484
      if (bh > 0)
Packit 5c3484
	{
Packit 5c3484
	  bit ^= al & bl;
Packit 5c3484
	  MP_LIMB_T_SWAP (al, bl);
Packit 5c3484
	  ah = bh;
Packit 5c3484
	  goto b_reduced;
Packit 5c3484
	}
Packit 5c3484
      goto ab_reduced;
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  while (bh > 0)
Packit 5c3484
    {
Packit 5c3484
      /* Compute (a|b) */
Packit 5c3484
      while (ah > bh)
Packit 5c3484
	{
Packit 5c3484
	  sub_ddmmss (ah, al, ah, al, bh, bl);
Packit 5c3484
	  if (al == 0)
Packit 5c3484
	    {
Packit 5c3484
	      count_trailing_zeros (c, ah);
Packit 5c3484
	      bit ^= ((GMP_NUMB_BITS + c) << 1) & (bl ^ (bl >> 1));
Packit 5c3484
Packit 5c3484
	      al = bl;
Packit 5c3484
	      bl = ah >> c;
Packit 5c3484
	      ah = bh;
Packit 5c3484
Packit 5c3484
	      bit ^= al & bl;
Packit 5c3484
	      goto b_reduced;
Packit 5c3484
	    }
Packit 5c3484
	  count_trailing_zeros (c, al);
Packit 5c3484
	  bit ^= (c << 1) & (bl ^ (bl >> 1));
Packit 5c3484
	  al = ((ah << (GMP_NUMB_BITS - c)) & GMP_NUMB_MASK) | (al >> c);
Packit 5c3484
	  ah >>= c;
Packit 5c3484
	}
Packit 5c3484
      if (ah == bh)
Packit 5c3484
	goto cancel_hi;
Packit 5c3484
Packit 5c3484
      if (ah == 0)
Packit 5c3484
	{
Packit 5c3484
	  bit ^= al & bl;
Packit 5c3484
	  MP_LIMB_T_SWAP (al, bl);
Packit 5c3484
	  ah = bh;
Packit 5c3484
	  break;
Packit 5c3484
	}
Packit 5c3484
Packit 5c3484
      bit ^= al & bl;
Packit 5c3484
Packit 5c3484
      /* Compute (b|a) */
Packit 5c3484
      while (bh > ah)
Packit 5c3484
	{
Packit 5c3484
	  sub_ddmmss (bh, bl, bh, bl, ah, al);
Packit 5c3484
	  if (bl == 0)
Packit 5c3484
	    {
Packit 5c3484
	      count_trailing_zeros (c, bh);
Packit 5c3484
	      bit ^= ((GMP_NUMB_BITS + c) << 1) & (al ^ (al >> 1));
Packit 5c3484
Packit 5c3484
	      bl = bh >> c;
Packit 5c3484
	      bit ^= al & bl;
Packit 5c3484
	      goto b_reduced;
Packit 5c3484
	    }
Packit 5c3484
	  count_trailing_zeros (c, bl);
Packit 5c3484
	  bit ^= (c << 1) & (al ^ (al >> 1));
Packit 5c3484
	  bl = ((bh << (GMP_NUMB_BITS - c)) & GMP_NUMB_MASK) | (bl >> c);
Packit 5c3484
	  bh >>= c;
Packit 5c3484
	}
Packit 5c3484
      bit ^= al & bl;
Packit 5c3484
Packit 5c3484
      /* Compute (a|b) */
Packit 5c3484
      if (ah == bh)
Packit 5c3484
	{
Packit 5c3484
	cancel_hi:
Packit 5c3484
	  if (al < bl)
Packit 5c3484
	    {
Packit 5c3484
	      MP_LIMB_T_SWAP (al, bl);
Packit 5c3484
	      bit ^= al & bl;
Packit 5c3484
	    }
Packit 5c3484
	  al -= bl;
Packit 5c3484
	  if (al == 0)
Packit 5c3484
	    return 0;
Packit 5c3484
Packit 5c3484
	  count_trailing_zeros (c, al);
Packit 5c3484
	  bit ^= (c << 1) & (bl ^ (bl >> 1));
Packit 5c3484
	  al >>= c;
Packit 5c3484
Packit 5c3484
	  if (al == 1)
Packit 5c3484
	    return 1 - (bit & 2);
Packit 5c3484
Packit 5c3484
	  MP_LIMB_T_SWAP (al, bl);
Packit 5c3484
	  bit ^= al & bl;
Packit 5c3484
	  break;
Packit 5c3484
	}
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
 b_reduced:
Packit 5c3484
  /* Compute (a|b), with b a single limb. */
Packit 5c3484
  ASSERT (bl & 1);
Packit 5c3484
Packit 5c3484
  if (bl == 1)
Packit 5c3484
    /* (a|1) = 1 */
Packit 5c3484
    return 1 - (bit & 2);
Packit 5c3484
Packit 5c3484
  while (ah > 0)
Packit 5c3484
    {
Packit 5c3484
      ah -= (al < bl);
Packit 5c3484
      al -= bl;
Packit 5c3484
      if (al == 0)
Packit 5c3484
	{
Packit 5c3484
	  if (ah == 0)
Packit 5c3484
	    return 0;
Packit 5c3484
	  count_trailing_zeros (c, ah);
Packit 5c3484
	  bit ^= ((GMP_NUMB_BITS + c) << 1) & (bl ^ (bl >> 1));
Packit 5c3484
	  al = ah >> c;
Packit 5c3484
	  goto ab_reduced;
Packit 5c3484
	}
Packit 5c3484
      count_trailing_zeros (c, al);
Packit 5c3484
Packit 5c3484
      al = ((ah << (GMP_NUMB_BITS - c)) & GMP_NUMB_MASK) | (al >> c);
Packit 5c3484
      ah >>= c;
Packit 5c3484
      bit ^= (c << 1) & (bl ^ (bl >> 1));
Packit 5c3484
    }
Packit 5c3484
 ab_reduced:
Packit 5c3484
  ASSERT (bl & 1);
Packit 5c3484
  ASSERT (bl > 1);
Packit 5c3484
Packit 5c3484
  return mpn_jacobi_base (al, bl, bit);
Packit 5c3484
}
Packit 5c3484
#else
Packit 5c3484
#error Unsupported value for JACOBI_2_METHOD
Packit 5c3484
#endif