예제 #1
0
int
mpz_millerrabin (mpz_srcptr n, int reps)
{
  int r;
  mpz_t nm1, nm3, x, y, q;
  unsigned long int k;
  gmp_randstate_t rstate;
  int is_prime;
  TMP_DECL;
  TMP_MARK;

  MPZ_TMP_INIT (nm1, SIZ (n) + 1);
  mpz_sub_ui (nm1, n, 1L);

  MPZ_TMP_INIT (x, SIZ (n) + 1);
  MPZ_TMP_INIT (y, 2 * SIZ (n)); /* mpz_powm_ui needs excessive memory!!! */

  /* Perform a Fermat test.  */
  mpz_set_ui (x, 210L);
  mpz_powm (y, x, nm1, n);
  if (mpz_cmp_ui (y, 1L) != 0)
    {
      TMP_FREE;
      return 0;
    }

  MPZ_TMP_INIT (q, SIZ (n));

  /* Find q and k, where q is odd and n = 1 + 2**k * q.  */
  k = mpz_scan1 (nm1, 0L);
  mpz_tdiv_q_2exp (q, nm1, k);

  /* n-3 */
  MPZ_TMP_INIT (nm3, SIZ (n) + 1);
  mpz_sub_ui (nm3, n, 3L);
  ASSERT (mpz_cmp_ui (nm3, 1L) >= 0);

  gmp_randinit_default (rstate);

  is_prime = 1;
  for (r = 0; r < reps && is_prime; r++)
    {
      /* 2 to n-2 inclusive, don't want 1, 0 or -1 */
      mpz_urandomm (x, rstate, nm3);
      mpz_add_ui (x, x, 2L);

      is_prime = millerrabin (n, nm1, x, y, q, k);
    }

  gmp_randclear (rstate);

  TMP_FREE;
  return is_prime;
}
예제 #2
0
void
mpz_cdiv_qr (mpz_ptr quot, mpz_ptr rem, mpz_srcptr dividend, mpz_srcptr divisor)
{
  mp_size_t divisor_size = SIZ (divisor);
  mp_size_t xsize;
  mpz_t temp_divisor;		/* N.B.: lives until function returns! */
  TMP_DECL;

  TMP_MARK;

  /* We need the original value of the divisor after the quotient and
     remainder have been preliminary calculated.  We have to copy it to
     temporary space if it's the same variable as either QUOT or REM.  */
  if (quot == divisor || rem == divisor)
    {
      MPZ_TMP_INIT (temp_divisor, (int) ABS (divisor_size)); // (int) added by PM
      mpz_set (temp_divisor, divisor);
      divisor = temp_divisor;
    }

  xsize = SIZ (dividend) ^ divisor_size;;
  mpz_tdiv_qr (quot, rem, dividend, divisor);

  if (xsize >= 0 && SIZ (rem) != 0)
    {
      mpz_add_ui (quot, quot, 1L);
      mpz_sub (rem, rem, divisor);
    }

  TMP_FREE;
}
예제 #3
0
파일: mod.c 프로젝트: mahdiz/mpclib
void
mpz_mod (mpz_ptr rem, mpz_srcptr dividend, mpz_srcptr divisor)
{
  mp_size_t divisor_size = divisor->_mp_size;
  mpz_t temp_divisor;		/* N.B.: lives until function returns! */
  TMP_DECL (marker);

  TMP_MARK (marker);

  /* We need the original value of the divisor after the remainder has been
     preliminary calculated.  We have to copy it to temporary space if it's
     the same variable as REM.  */
  if (rem == divisor)
    {
      MPZ_TMP_INIT (temp_divisor, ABS (divisor_size));
      mpz_set (temp_divisor, divisor);
      divisor = temp_divisor;
    }

  mpz_tdiv_r (rem, dividend, divisor);

  if (rem->_mp_size != 0)
    {
      if (dividend->_mp_size < 0)
	{
	  if (divisor->_mp_size < 0)
	    mpz_sub (rem, rem, divisor);
	  else
	    mpz_add (rem, rem, divisor);
	}
    }

  TMP_FREE (marker);
}
예제 #4
0
파일: fdiv_qr.c 프로젝트: mahdiz/mpclib
void
mpz_fdiv_qr (mpz_ptr quot, mpz_ptr rem, mpz_srcptr dividend, mpz_srcptr divisor)
{
  mp_size_t divisor_size = divisor->_mp_size;
  mp_size_t xsize;
  mpz_t temp_divisor;		/* N.B.: lives until function returns! */
  TMP_DECL (marker);

  TMP_MARK (marker);

  /* We need the original value of the divisor after the quotient and
     remainder have been preliminary calculated.  We have to copy it to
     temporary space if it's the same variable as either QUOT or REM.  */
  if (quot == divisor || rem == divisor)
    {
      MPZ_TMP_INIT (temp_divisor, ABS (divisor_size));
      mpz_set (temp_divisor, divisor);
      divisor = temp_divisor;
    }

  xsize = dividend->_mp_size ^ divisor_size;;
  mpz_tdiv_qr (quot, rem, dividend, divisor);

  if (xsize < 0 && rem->_mp_size != 0)
    {
      mpz_sub_ui (quot, quot, 1L);
      mpz_add (rem, rem, divisor);
    }

  TMP_FREE (marker);
}
예제 #5
0
void
mpz_fdiv_r (mpz_ptr rem, mpz_srcptr dividend, mpz_srcptr divisor)
{
  mp_size_t divisor_size = SIZ (divisor);
  mpz_t temp_divisor;		/* N.B.: lives until function returns! */
  TMP_DECL;

  TMP_MARK;

  /* We need the original value of the divisor after the remainder has been
     preliminary calculated.  We have to copy it to temporary space if it's
     the same variable as REM.  */
  if (rem == divisor)
    {
      MPZ_TMP_INIT (temp_divisor, ABS (divisor_size));
      mpz_set (temp_divisor, divisor);
      divisor = temp_divisor;
    }

  mpz_tdiv_r (rem, dividend, divisor);

  if ((divisor_size ^ SIZ (dividend)) < 0 && SIZ (rem) != 0)
    mpz_add (rem, rem, divisor);

  TMP_FREE;
}
예제 #6
0
파일: invert.c 프로젝트: mahdiz/mpclib
int
mpz_invert (mpz_ptr inverse, mpz_srcptr x, mpz_srcptr n)
{
  mpz_t gcd, tmp;
  mp_size_t xsize, nsize, size;
  TMP_DECL (marker);

  xsize = SIZ (x);
  nsize = SIZ (n);
  xsize = ABS (xsize);
  nsize = ABS (nsize);
  size = MAX (xsize, nsize) + 1;

  /* No inverse exists if the leftside operand is 0.  Likewise, no
     inverse exists if the mod operand is 1.  */
  if (xsize == 0 || (nsize == 1 && (PTR (n))[0] == 1))
    return 0;

  TMP_MARK (marker);

  MPZ_TMP_INIT (gcd, size);
  MPZ_TMP_INIT (tmp, size);
  mpz_gcdext (gcd, tmp, (mpz_ptr) 0, x, n);

  /* If no inverse existed, return with an indication of that.  */
  if (SIZ (gcd) != 1 || PTR(gcd)[0] != 1)
    {
      TMP_FREE (marker);
      return 0;
    }

  /* Make sure we return a positive inverse.  */
  if (SIZ (tmp) < 0)
    {
      if (SIZ (n) < 0)
	mpz_sub (inverse, tmp, n);
      else
	mpz_add (inverse, tmp, n);
    }
  else
    mpz_set (inverse, tmp);

  TMP_FREE (marker);
  return 1;
}
예제 #7
0
파일: lcm.c 프로젝트: bngabonziza/miktex
void
mpz_lcm (mpz_ptr r, mpz_srcptr u, mpz_srcptr v)
{
  mpz_t g;
  mp_size_t usize, vsize;
  TMP_DECL;

  usize = SIZ (u);
  vsize = SIZ (v);
  if (usize == 0 || vsize == 0)
    {
      SIZ (r) = 0;
      return;
    }
  usize = ABS (usize);
  vsize = ABS (vsize);

  if (vsize == 1 || usize == 1)
    {
      mp_limb_t  vl, gl, c;
      mp_srcptr  up;
      mp_ptr     rp;

      if (usize == 1)
	{
	  usize = vsize;
	  MPZ_SRCPTR_SWAP (u, v);
	}

      MPZ_REALLOC (r, usize+1);

      up = PTR(u);
      vl = PTR(v)[0];
      gl = mpn_gcd_1 (up, usize, vl);
      vl /= gl;

      rp = PTR(r);
      c = mpn_mul_1 (rp, up, usize, vl);
      rp[usize] = c;
      usize += (c != 0);
      SIZ(r) = usize;
      return;
    }

  TMP_MARK;
  MPZ_TMP_INIT (g, usize); /* v != 0 implies |gcd(u,v)| <= |u| */

  mpz_gcd (g, u, v);
  mpz_divexact (g, u, g);
  mpz_mul (r, g, v);

  SIZ (r) = ABS (SIZ (r));	/* result always positive */

  TMP_FREE;
}
예제 #8
0
파일: t-bdiv.c 프로젝트: AllardJ/Tomato
mp_limb_t
random_word (gmp_randstate_ptr rs)
{
  mpz_t x;
  mp_limb_t r;
  TMP_DECL;
  TMP_MARK;

  MPZ_TMP_INIT (x, 2);
  mpz_urandomb (x, rs, 32);
  r = mpz_get_ui (x);
  TMP_FREE;
  return r;
}
예제 #9
0
파일: fdiv_q.c 프로젝트: 119/aircam-openwrt
void
mpz_fdiv_q (mpz_ptr quot, mpz_srcptr dividend, mpz_srcptr divisor)
{
  mp_size_t dividend_size = dividend->_mp_size;
  mp_size_t divisor_size = divisor->_mp_size;
  mpz_t rem;
  TMP_DECL;

  TMP_MARK;

  MPZ_TMP_INIT (rem, ABS (divisor_size));

  mpz_tdiv_qr (quot, rem, dividend, divisor);

  if ((divisor_size ^ dividend_size) < 0 && rem->_mp_size != 0)
    mpz_sub_ui (quot, quot, 1L);

  TMP_FREE;
}
예제 #10
0
void
mpz_cdiv_q (mpz_ptr quot, mpz_srcptr dividend, mpz_srcptr divisor)
{
  mp_size_t dividend_size = SIZ (dividend);
  mp_size_t divisor_size = SIZ (divisor);
  mpz_t rem;
  TMP_DECL;

  TMP_MARK;

  MPZ_TMP_INIT (rem, ABS (divisor_size));

  mpz_tdiv_qr (quot, rem, dividend, divisor);

  if ((divisor_size ^ dividend_size) >= 0 && SIZ (rem) != 0)
    mpz_add_ui (quot, quot, 1L);

  TMP_FREE;
}
예제 #11
0
void
mpz_gcdext (mpz_ptr g, mpz_ptr s, mpz_ptr t, mpz_srcptr a, mpz_srcptr b)
{
  mp_size_t asize, bsize, usize, vsize;
  mp_srcptr ap, bp;
  mp_ptr up, vp;
  mp_size_t gsize, ssize, tmp_ssize;
  mp_ptr gp, sp, tmp_gp, tmp_sp;
  mpz_srcptr u, v;
  mpz_ptr ss, tt;
  __mpz_struct stmp, gtmp;
  TMP_DECL;

  TMP_MARK;

  /* mpn_gcdext requires that U >= V.  Therefore, we often have to swap U and
     V.  This in turn leads to a lot of complications.  The computed cofactor
     will be the wrong one, so we have to fix that up at the end.  */

  asize = ABS (SIZ (a));
  bsize = ABS (SIZ (b));
  ap = PTR (a);
  bp = PTR (b);
  if (asize > bsize || (asize == bsize && mpn_cmp (ap, bp, asize) > 0))
    {
      usize = asize;
      vsize = bsize;
      up = (mp_ptr) TMP_ALLOC ((usize + 1) * BYTES_PER_MP_LIMB);
      vp = (mp_ptr) TMP_ALLOC ((vsize + 1) * BYTES_PER_MP_LIMB);
      MPN_COPY (up, ap, usize);
      MPN_COPY (vp, bp, vsize);
      u = a;
      v = b;
      ss = s;
      tt = t;
    }
  else
    {
      usize = bsize;
      vsize = asize;
      up = (mp_ptr) TMP_ALLOC ((usize + 1) * BYTES_PER_MP_LIMB);
      vp = (mp_ptr) TMP_ALLOC ((vsize + 1) * BYTES_PER_MP_LIMB);
      MPN_COPY (up, bp, usize);
      MPN_COPY (vp, ap, vsize);
      u = b;
      v = a;
      ss = t;
      tt = s;
    }

  tmp_gp = (mp_ptr) TMP_ALLOC ((usize + 1) * BYTES_PER_MP_LIMB);
  tmp_sp = (mp_ptr) TMP_ALLOC ((usize + 1) * BYTES_PER_MP_LIMB);

  if (vsize == 0)
    {
      tmp_sp[0] = 1;
      tmp_ssize = 1;
      MPN_COPY (tmp_gp, up, usize);
      gsize = usize;
    }
  else
    gsize = mpn_gcdext (tmp_gp, tmp_sp, &tmp_ssize, up, usize, vp, vsize);
  ssize = ABS (tmp_ssize);

  PTR (&gtmp) = tmp_gp;
  SIZ (&gtmp) = gsize;

  PTR (&stmp) = tmp_sp;
  SIZ (&stmp) = (tmp_ssize ^ SIZ (u)) >= 0 ? ssize : -ssize;

  if (tt != NULL)
    {
      if (SIZ (v) == 0)
	SIZ (tt) = 0;
      else
	{
	  mpz_t x;
	  MPZ_TMP_INIT (x, ssize + usize + 1);
	  mpz_mul (x, &stmp, u);
	  mpz_sub (x, &gtmp, x);
	  mpz_tdiv_q (tt, x, v);
	}
    }

  if (ss != NULL)
    {
      if (ALLOC (ss) < ssize)
	_mpz_realloc (ss, ssize);
      sp = PTR (ss);
      MPN_COPY (sp, tmp_sp, ssize);
      SIZ (ss) = SIZ (&stmp);
    }

  if (ALLOC (g) < gsize)
    _mpz_realloc (g, gsize);
  gp = PTR (g);
  MPN_COPY (gp, tmp_gp, gsize);
  SIZ (g) = gsize;

  TMP_FREE;
}
예제 #12
0
int
mpz_perfect_power_p (mpz_srcptr u)
{
  unsigned long int prime;
  unsigned long int n, n2;
  int i;
  unsigned long int rem;
  mpz_t u2, q;
  int exact;
  mp_size_t uns;
  mp_size_t usize = SIZ (u);
  TMP_DECL;

  if (mpz_cmpabs_ui (u, 1) <= 0)
    return 1;			/* -1, 0, and +1 are perfect powers */

  n2 = mpz_scan1 (u, 0);
  if (n2 == 1)
    return 0;			/* 2 divides exactly once.  */

  TMP_MARK;

  uns = ABS (usize) - n2 / BITS_PER_MP_LIMB;
  MPZ_TMP_INIT (q, uns);
  MPZ_TMP_INIT (u2, uns);

  mpz_tdiv_q_2exp (u2, u, n2);
  mpz_abs (u2, u2);

  if (mpz_cmp_ui (u2, 1) == 0)
    {
      TMP_FREE;
      /* factoring completed; consistent power */
      return ! (usize < 0 && POW2P(n2));
    }

  if (isprime (n2))
    goto n2prime;

  for (i = 1; primes[i] != 0; i++)
    {
      prime = primes[i];

      if (mpz_cmp_ui (u2, prime) < 0)
	break;

      if (mpz_divisible_ui_p (u2, prime))	/* divisible by this prime? */
	{
	  rem = mpz_tdiv_q_ui (q, u2, prime * prime);
	  if (rem != 0)
	    {
	      TMP_FREE;
	      return 0;		/* prime divides exactly once, reject */
	    }
	  mpz_swap (q, u2);
	  for (n = 2;;)
	    {
	      rem = mpz_tdiv_q_ui (q, u2, prime);
	      if (rem != 0)
		break;
	      mpz_swap (q, u2);
	      n++;
	    }

	  n2 = gcd (n2, n);
	  if (n2 == 1)
	    {
	      TMP_FREE;
	      return 0;		/* we have multiplicity 1 of some factor */
	    }

	  if (mpz_cmp_ui (u2, 1) == 0)
	    {
	      TMP_FREE;
	      /* factoring completed; consistent power */
	      return ! (usize < 0 && POW2P(n2));
	    }

	  /* As soon as n2 becomes a prime number, stop factoring.
	     Either we have u=x^n2 or u is not a perfect power.  */
	  if (isprime (n2))
	    goto n2prime;
	}
    }

  if (n2 == 0)
    {
      /* We found no factors above; have to check all values of n.  */
      unsigned long int nth;
      for (nth = usize < 0 ? 3 : 2;; nth++)
	{
	  if (! isprime (nth))
	    continue;
#if 0
	  exact = mpz_padic_root (q, u2, nth, PTH);
	  if (exact)
#endif
	    exact = mpz_root (q, u2, nth);
	  if (exact)
	    {
	      TMP_FREE;
	      return 1;
	    }
	  if (mpz_cmp_ui (q, SMALLEST_OMITTED_PRIME) < 0)
	    {
	      TMP_FREE;
	      return 0;
	    }
	}
    }
  else
    {
      unsigned long int nth;

      if (usize < 0 && POW2P(n2))
	{
	  TMP_FREE;
	  return 0;
	}

      /* We found some factors above.  We just need to consider values of n
	 that divides n2.  */
      for (nth = 2; nth <= n2; nth++)
	{
	  if (! isprime (nth))
	    continue;
	  if (n2 % nth != 0)
	    continue;
#if 0
	  exact = mpz_padic_root (q, u2, nth, PTH);
	  if (exact)
#endif
	    exact = mpz_root (q, u2, nth);
	  if (exact)
	    {
	      if (! (usize < 0 && POW2P(nth)))
		{
		  TMP_FREE;
		  return 1;
		}
	    }
	  if (mpz_cmp_ui (q, SMALLEST_OMITTED_PRIME) < 0)
	    {
	      TMP_FREE;
	      return 0;
	    }
	}

      TMP_FREE;
      return 0;
    }

n2prime:
  if (usize < 0 && POW2P(n2))
    {
      TMP_FREE;
      return 0;
    }

  exact = mpz_root (NULL, u2, n2);
  TMP_FREE;
  return exact;
}
예제 #13
0
void
mpz_gcdext (mpz_ptr g, mpz_ptr s, mpz_ptr t, mpz_srcptr a, mpz_srcptr b)
{
  mp_size_t asize, bsize;
  mp_ptr tmp_ap, tmp_bp;
  mp_size_t gsize, ssize, tmp_ssize;
  mp_ptr gp, tmp_gp, tmp_sp;
  TMP_DECL;

  /* mpn_gcdext requires that Usize >= Vsize.  Therefore, we often
     have to swap U and V.  The computed cofactor will be the
     "smallest" one, which is faster to produce.  The wanted one will
     be computed here; this is needed anyway when both are requested.  */

  asize = ABSIZ (a);
  bsize = ABSIZ (b);

  if (asize < bsize)
    {
      MPZ_SRCPTR_SWAP (a, b);
      MP_SIZE_T_SWAP (asize, bsize);
      MPZ_PTR_SWAP (s, t);
    }

  if (bsize == 0)
    {
      /* g = |a|, s = sgn(a), t = 0. */
      ssize = SIZ (a) >= 0 ? (asize != 0) : -1;

      gp = MPZ_REALLOC (g, asize);
      MPN_COPY (gp, PTR (a), asize);
      SIZ (g) = asize;

      if (t != NULL)
	SIZ (t) = 0;
      if (s != NULL)
	{
	  SIZ (s) = ssize;
	  PTR (s)[0] = 1;
	}
      return;
    }

  TMP_MARK;

  TMP_ALLOC_LIMBS_2 (tmp_ap, asize, tmp_bp, bsize);
  MPN_COPY (tmp_ap, PTR (a), asize);
  MPN_COPY (tmp_bp, PTR (b), bsize);

  TMP_ALLOC_LIMBS_2 (tmp_gp, bsize, tmp_sp, bsize + 1);

  gsize = mpn_gcdext (tmp_gp, tmp_sp, &tmp_ssize, tmp_ap, asize, tmp_bp, bsize);

  ssize = ABS (tmp_ssize);
  tmp_ssize = SIZ (a) >= 0 ? tmp_ssize : -tmp_ssize;

  if (t != NULL)
    {
      mpz_t x;
      __mpz_struct gtmp, stmp;

      PTR (&gtmp) = tmp_gp;
      SIZ (&gtmp) = gsize;

      PTR (&stmp) = tmp_sp;
      SIZ (&stmp) = tmp_ssize;

      MPZ_TMP_INIT (x, ssize + asize + 1);
      mpz_mul (x, &stmp, a);
      mpz_sub (x, &gtmp, x);
      mpz_divexact (t, x, b);
    }

  if (s != NULL)
    {
      mp_ptr sp;

      sp = MPZ_REALLOC (s, ssize);
      MPN_COPY (sp, tmp_sp, ssize);
      SIZ (s) = tmp_ssize;
    }

  gp = MPZ_REALLOC (g, gsize);
  MPN_COPY (gp, tmp_gp, gsize);
  SIZ (g) = gsize;

  TMP_FREE;
}
예제 #14
0
파일: powm.c 프로젝트: mahdiz/mpclib
/* For now, also disable REDC when MOD is even, as the inverse can't handle
   that.  At some point, we might want to make the code faster for that case,
   perhaps using CRR.  */

#ifndef POWM_THRESHOLD
#define POWM_THRESHOLD  ((8 * SQR_KARATSUBA_THRESHOLD) / 3)
#endif

#define HANDLE_NEGATIVE_EXPONENT 1
#undef REDUCE_EXPONENT

void
#ifndef BERKELEY_MP
mpz_powm (mpz_ptr r, mpz_srcptr b, mpz_srcptr e, mpz_srcptr m)
#else /* BERKELEY_MP */
pow (mpz_srcptr b, mpz_srcptr e, mpz_srcptr m, mpz_ptr r)
#endif /* BERKELEY_MP */
{
  mp_ptr xp, tp, qp, gp, this_gp;
  mp_srcptr bp, ep, mp;
  mp_size_t bn, es, en, mn, xn;
  mp_limb_t invm, c;
  unsigned long int enb;
  mp_size_t i, K, j, l, k;
  int m_zero_cnt, e_zero_cnt;
  int sh;
  int use_redc;
#if HANDLE_NEGATIVE_EXPONENT
  mpz_t new_b;
#endif
#if REDUCE_EXPONENT
  mpz_t new_e;
#endif
  TMP_DECL (marker);

  mp = PTR(m);
  mn = ABSIZ (m);
  if (mn == 0)
    DIVIDE_BY_ZERO;

  TMP_MARK (marker);

  es = SIZ (e);
  if (es <= 0)
    {
      if (es == 0)
	{
	  /* Exponent is zero, result is 1 mod m, i.e., 1 or 0 depending on if
	     m equals 1.  */
	  SIZ(r) = (mn == 1 && mp[0] == 1) ? 0 : 1;
	  PTR(r)[0] = 1;
	  TMP_FREE (marker);	/* we haven't really allocated anything here */
	  return;
	}
#if HANDLE_NEGATIVE_EXPONENT
      MPZ_TMP_INIT (new_b, mn + 1);

      if (! mpz_invert (new_b, b, m))
	DIVIDE_BY_ZERO;
      b = new_b;
      es = -es;
#else
      DIVIDE_BY_ZERO;
#endif
    }
  en = es;

#if REDUCE_EXPONENT
  /* Reduce exponent by dividing it by phi(m) when m small.  */
  if (mn == 1 && mp[0] < 0x7fffffffL && en * GMP_NUMB_BITS > 150)
    {
      MPZ_TMP_INIT (new_e, 2);
      mpz_mod_ui (new_e, e, phi (mp[0]));
      e = new_e;
    }
#endif

  use_redc = mn < POWM_THRESHOLD && mp[0] % 2 != 0;
  if (use_redc)
    {
      /* invm = -1/m mod 2^BITS_PER_MP_LIMB, must have m odd */
      modlimb_invert (invm, mp[0]);
      invm = -invm;
    }
  else
    {
      /* Normalize m (i.e. make its most significant bit set) as required by
	 division functions below.  */
      count_leading_zeros (m_zero_cnt, mp[mn - 1]);
      m_zero_cnt -= GMP_NAIL_BITS;
      if (m_zero_cnt != 0)
	{
	  mp_ptr new_mp;
	  new_mp = TMP_ALLOC_LIMBS (mn);
	  mpn_lshift (new_mp, mp, mn, m_zero_cnt);
	  mp = new_mp;
	}
    }

  /* Determine optimal value of k, the number of exponent bits we look at
     at a time.  */
  count_leading_zeros (e_zero_cnt, PTR(e)[en - 1]);
  e_zero_cnt -= GMP_NAIL_BITS;
  enb = en * GMP_NUMB_BITS - e_zero_cnt; /* number of bits of exponent */
  k = 1;
  K = 2;
  while (2 * enb > K * (2 + k * (3 + k)))
    {
      k++;
      K *= 2;
    }

  tp = TMP_ALLOC_LIMBS (2 * mn + 1);
  qp = TMP_ALLOC_LIMBS (mn + 1);

  gp = __GMP_ALLOCATE_FUNC_LIMBS (K / 2 * mn);

  /* Compute x*R^n where R=2^BITS_PER_MP_LIMB.  */
  bn = ABSIZ (b);
  bp = PTR(b);
  /* Handle |b| >= m by computing b mod m.  FIXME: It is not strictly necessary
     for speed or correctness to do this when b and m have the same number of
     limbs, perhaps remove mpn_cmp call.  */
  if (bn > mn || (bn == mn && mpn_cmp (bp, mp, mn) >= 0))
    {
      /* Reduce possibly huge base while moving it to gp[0].  Use a function
	 call to reduce, since we don't want the quotient allocation to
	 live until function return.  */
      if (use_redc)
	{
	  reduce (tp + mn, bp, bn, mp, mn);	/* b mod m */
	  MPN_ZERO (tp, mn);
	  mpn_tdiv_qr (qp, gp, 0L, tp, 2 * mn, mp, mn); /* unnormnalized! */
	}
      else
	{
	  reduce (gp, bp, bn, mp, mn);
	}
    }
  else
    {
      /* |b| < m.  We pad out operands to become mn limbs,  which simplifies
	 the rest of the function, but slows things down when the |b| << m.  */
      if (use_redc)
	{
	  MPN_ZERO (tp, mn);
	  MPN_COPY (tp + mn, bp, bn);
	  MPN_ZERO (tp + mn + bn, mn - bn);
	  mpn_tdiv_qr (qp, gp, 0L, tp, 2 * mn, mp, mn);
	}
      else
	{
	  MPN_COPY (gp, bp, bn);
	  MPN_ZERO (gp + bn, mn - bn);
	}
    }

  /* Compute xx^i for odd g < 2^i.  */

  xp = TMP_ALLOC_LIMBS (mn);
  mpn_sqr_n (tp, gp, mn);
  if (use_redc)
    redc (xp, mp, mn, invm, tp);		/* xx = x^2*R^n */
  else
    mpn_tdiv_qr (qp, xp, 0L, tp, 2 * mn, mp, mn);
  this_gp = gp;
  for (i = 1; i < K / 2; i++)
    {
      mpn_mul_n (tp, this_gp, xp, mn);
      this_gp += mn;
      if (use_redc)
	redc (this_gp, mp, mn, invm, tp);	/* g[i] = x^(2i+1)*R^n */
      else
	mpn_tdiv_qr (qp, this_gp, 0L, tp, 2 * mn, mp, mn);
    }

  /* Start the real stuff.  */
  ep = PTR (e);
  i = en - 1;				/* current index */
  c = ep[i];				/* current limb */
  sh = GMP_NUMB_BITS - e_zero_cnt;	/* significant bits in ep[i] */
  sh -= k;				/* index of lower bit of ep[i] to take into account */
  if (sh < 0)
    {					/* k-sh extra bits are needed */
      if (i > 0)
	{
	  i--;
	  c <<= (-sh);
	  sh += GMP_NUMB_BITS;
	  c |= ep[i] >> sh;
	}
    }