Ejemplo n.º 1
0
Archivo: set.c Proyecto: Cl3Kener/gmp
void
mpq_set (mpq_ptr dest, mpq_srcptr src)
{
  mp_size_t num_size, den_size;
  mp_size_t abs_num_size;
  mp_ptr dp;

  num_size = SIZ(NUM(src));
  SIZ(NUM(dest)) = num_size;
  abs_num_size = ABS (num_size);
  dp = MPZ_NEWALLOC (NUM(dest), abs_num_size);
  MPN_COPY (dp, PTR(NUM(src)), abs_num_size);

  den_size = SIZ(DEN(src));
  SIZ(DEN(dest)) = den_size;
  dp = MPZ_NEWALLOC (DEN(dest), den_size);
  MPN_COPY (dp, PTR(DEN(src)), den_size);
}
Ejemplo n.º 2
0
void
mpq_abs (mpq_ptr dst, mpq_srcptr src)
{
  mp_size_t  num_abs_size = ABSIZ(NUM(src));

  if (dst != src)
    {
      mp_size_t  den_size = SIZ(DEN(src));
      mp_ptr dp;

      dp = MPZ_NEWALLOC (NUM(dst), num_abs_size);
      MPN_COPY (dp, PTR(NUM(src)), num_abs_size);

      dp = MPZ_NEWALLOC (DEN(dst), den_size);
      SIZ(DEN(dst)) = den_size;
      MPN_COPY (dp, PTR(DEN(src)), den_size);
    }

  SIZ(NUM(dst)) = num_abs_size;
}
Ejemplo n.º 3
0
void
mpq_set_num (mpq_ptr dest, mpz_srcptr num)
{
  mp_size_t size = SIZ (num);
  mp_size_t abs_size = ABS (size);
  mp_ptr dp;

  dp = MPZ_NEWALLOC (NUM(dest), abs_size);

  SIZ(NUM(dest)) = size;
  MPN_COPY (dp, PTR(num), abs_size);
}
Ejemplo n.º 4
0
void
mpq_set_den (mpq_ptr dest, mpz_srcptr den)
{
  mp_size_t size = SIZ (den);
  mp_size_t abs_size = ABS (size);
  mp_ptr dp;

  dp = MPZ_NEWALLOC (DEN(dest), abs_size);

  SIZ(DEN(dest)) = size;
  MPN_COPY (dp, PTR(den), abs_size);
}
Ejemplo n.º 5
0
void
mpq_inv (mpq_ptr dest, mpq_srcptr src)
{
  mp_size_t num_size = SIZ(NUM(src));
  mp_size_t den_size = SIZ(DEN(src));

  if (num_size < 0)
    {
      num_size = -num_size;
      den_size = -den_size;
    }
  else if (UNLIKELY (num_size == 0))
    DIVIDE_BY_ZERO;

  SIZ(DEN(dest)) = num_size;
  SIZ(NUM(dest)) = den_size;

  /* If dest == src we may just swap the numerator and denominator;
     we ensured that the new denominator is positive.  */

  if (dest == src)
    {
      MP_PTR_SWAP (PTR(NUM(dest)), PTR(DEN(dest)));
      MP_SIZE_T_SWAP (ALLOC(NUM(dest)), ALLOC(DEN(dest)));
    }
  else
    {
      mp_ptr dp;

      den_size = ABS (den_size);
      dp = MPZ_NEWALLOC (NUM(dest), den_size);
      MPN_COPY (dp, PTR(DEN(src)), den_size);

      dp = MPZ_NEWALLOC (DEN(dest), num_size);
      MPN_COPY (dp, PTR(NUM(src)), num_size);
    }
}
Ejemplo n.º 6
0
void
mpz_rrandomb (mpz_ptr x, gmp_randstate_t rstate, mp_bitcnt_t nbits)
{
  mp_size_t nl;
  mp_ptr xp;

  nl = BITS_TO_LIMBS (nbits);
  if (nbits != 0)
    {
      xp = MPZ_NEWALLOC (x, nl);
      gmp_rrandomb (xp, rstate, nbits);
    }

  SIZ(x) = nl;
}
Ejemplo n.º 7
0
Archivo: set_ui.c Proyecto: waallen/gmp
void
mpz_set_ui (mpz_ptr dest, unsigned long int val)
{
  mp_size_t size;

  MPZ_NEWALLOC (dest, 1)[0] = val & GMP_NUMB_MASK;
  size = val != 0;

#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
  if (val > GMP_NUMB_MAX)
    {
      MPZ_REALLOC (dest, 2);
      PTR (dest)[1] = val >> GMP_NUMB_BITS;
      size = 2;
    }
Ejemplo n.º 8
0
void
mpz_fib2_ui (mpz_ptr fn, mpz_ptr fnsub1, unsigned long n)
{
  mp_ptr     fp, f1p;
  mp_size_t  size;

  if (n <= FIB_TABLE_LIMIT)
    {
      MPZ_NEWALLOC (fn, 1)[0] = FIB_TABLE (n);
      SIZ(fn) = (n != 0);      /* F[0]==0, others are !=0 */
      MPZ_NEWALLOC (fnsub1, 1)[0] = FIB_TABLE ((int) n - 1);
      SIZ(fnsub1) = (n != 1);  /* F[1-1]==0, others are !=0 */
      return;
    }

  size = MPN_FIB2_SIZE (n);
  fp =  MPZ_NEWALLOC (fn,     size);
  f1p = MPZ_NEWALLOC (fnsub1, size);

  size = mpn_fib2_ui (fp, f1p, n);

  SIZ(fn)     = size;
  SIZ(fnsub1) = size - (f1p[size-1] == 0);
}
Ejemplo n.º 9
0
void
mpq_set_z (mpq_ptr dest, mpz_srcptr src)
{
  mp_size_t num_size;
  mp_size_t abs_num_size;
  mp_ptr dp;

  num_size = SIZ (src);
  abs_num_size = ABS (num_size);
  dp = MPZ_NEWALLOC (NUM(dest), abs_num_size);
  SIZ(NUM(dest)) = num_size;
  MPN_COPY (dp, PTR(src), abs_num_size);

  PTR(DEN(dest))[0] = 1;
  SIZ(DEN(dest)) = 1;
}
Ejemplo n.º 10
0
void
gmp_randinit_lc_2exp (gmp_randstate_t rstate,
                      mpz_srcptr a,
                      unsigned long int c,
                      mp_bitcnt_t m2exp)
{
    gmp_rand_lc_struct *p;
    mp_size_t seedn = BITS_TO_LIMBS (m2exp);

    ASSERT_ALWAYS (m2exp != 0);

    p = __GMP_ALLOCATE_FUNC_TYPE (1, gmp_rand_lc_struct);
    RNG_STATE (rstate) = (mp_limb_t *) (void *) p;
    RNG_FNPTR (rstate) = (void *) &Linear_Congruential_Generator;

    /* allocate m2exp bits of space for p->_mp_seed, and initial seed "1" */
    mpz_init2 (p->_mp_seed, m2exp);
    MPN_ZERO (PTR (p->_mp_seed), seedn);
    SIZ (p->_mp_seed) = seedn;
    PTR (p->_mp_seed)[0] = 1;

    /* "a", forced to 0 to 2^m2exp-1 */
    mpz_init (p->_mp_a);
    mpz_fdiv_r_2exp (p->_mp_a, a, m2exp);

    /* Avoid SIZ(a) == 0 to avoid checking for special case in lc().  */
    if (SIZ (p->_mp_a) == 0)
    {
        SIZ (p->_mp_a) = 1;
        MPZ_NEWALLOC (p->_mp_a, 1)[0] = CNST_LIMB (0);
    }

    MPN_SET_UI (p->_cp, p->_cn, c);

    /* Internally we may discard any bits of c above m2exp.  The following
       code ensures that __GMPN_ADD in lc() will always work.  */
    if (seedn < p->_cn)
        p->_cn = (p->_cp[0] != 0);

    p->_mp_m2exp = m2exp;
}
Ejemplo n.º 11
0
void
mpz_neg (mpz_ptr w, mpz_srcptr u)
{
  mp_ptr wp;
  mp_srcptr up;
  mp_size_t usize, size;

  usize = SIZ (u);

  if (u != w)
    {
      size = ABS (usize);

      wp = MPZ_NEWALLOC (w, size);

      up = PTR (u);

      MPN_COPY (wp, up, size);
    }

  SIZ (w) = -usize;
}
Ejemplo n.º 12
0
size_t
mpz_inp_raw (mpz_ptr x, FILE *fp)
{
  unsigned char  csize_bytes[4];
  mp_size_t      csize, abs_xsize, i;
  size_t         abs_csize;
  char           *cp;
  mp_ptr         xp, sp, ep;
  mp_limb_t      slimb, elimb;

  if (fp == 0)
    fp = stdin;

  /* 4 bytes for size */
  if (fread (csize_bytes, sizeof (csize_bytes), 1, fp) != 1)
    return 0;

  csize =
    (  (mp_size_t) csize_bytes[0] << 24)
    + ((mp_size_t) csize_bytes[1] << 16)
    + ((mp_size_t) csize_bytes[2] << 8)
    + ((mp_size_t) csize_bytes[3]);

  /* Sign extend if necessary.
     Could write "csize -= ((csize & 0x80000000L) << 1)", but that tickles a
     bug in gcc 3.0 for powerpc64 on AIX.  */
  if (sizeof (csize) > 4 && csize & 0x80000000L)
    csize -= 0x80000000L << 1;

  abs_csize = ABS (csize);

  /* round up to a multiple of limbs */
  abs_xsize = BITS_TO_LIMBS (abs_csize*8);

  if (abs_xsize != 0)
    {
      xp = MPZ_NEWALLOC (x, abs_xsize);

      /* Get limb boundaries right in the read, for the benefit of the
	 non-nails case.  */
      xp[0] = 0;
      cp = (char *) (xp + abs_xsize) - abs_csize;
      if (fread (cp, abs_csize, 1, fp) != 1)
	return 0;

      if (GMP_NAIL_BITS == 0)
	{
	  /* Reverse limbs to least significant first, and byte swap.  If
	     abs_xsize is odd then on the last iteration elimb and slimb are
	     the same.  It doesn't seem extra code to handle that case
	     separately, to save an NTOH.  */
	  sp = xp;
	  ep = xp + abs_xsize-1;
	  for (i = 0; i < (abs_xsize+1)/2; i++)
	    {
	      NTOH_LIMB_FETCH (elimb, ep);
	      NTOH_LIMB_FETCH (slimb, sp);
	      *sp++ = elimb;
	      *ep-- = slimb;
	    }
	}
      else
	{
	  /* It ought to be possible to do the transformation in-place, but
	     for now it's easier to use an extra temporary area.  */
	  mp_limb_t  byte, limb;
	  int	     bits;
	  mp_size_t  tpos;
	  mp_ptr     tp;
	  TMP_DECL;

	  TMP_MARK;
	  tp = TMP_ALLOC_LIMBS (abs_xsize);
	  limb = 0;
	  bits = 0;
	  tpos = 0;
	  for (i = abs_csize-1; i >= 0; i--)
	    {
	      byte = (unsigned char) cp[i];
	      limb |= (byte << bits);
	      bits += 8;
	      if (bits >= GMP_NUMB_BITS)
		{
		  ASSERT (tpos < abs_xsize);
		  tp[tpos++] = limb & GMP_NUMB_MASK;
		  bits -= GMP_NUMB_BITS;
		  ASSERT (bits < 8);
		  limb = byte >> (8 - bits);
		}
	    }
	  if (bits != 0)
	    {
	      ASSERT (tpos < abs_xsize);
	      tp[tpos++] = limb;
	    }
	  ASSERT (tpos == abs_xsize);

	  MPN_COPY (xp, tp, abs_xsize);
	  TMP_FREE;
	}
Ejemplo n.º 13
0
void
mpq_set_f (mpq_ptr q, mpf_srcptr f)
{
  mp_size_t  fexp = EXP(f);
  mp_ptr     fptr = PTR(f);
  mp_size_t  fsize = SIZ(f);
  mp_size_t  abs_fsize = ABS(fsize);
  mp_limb_t  flow;

  if (fsize == 0)
    {
      /* set q=0 */
      SIZ(NUM(q)) = 0;
      SIZ(DEN(q)) = 1;
      PTR(DEN(q))[0] = 1;
      return;
    }

  /* strip low zero limbs from f */
  flow = *fptr;
  MPN_STRIP_LOW_ZEROS_NOT_ZERO (fptr, abs_fsize, flow);

  if (fexp >= abs_fsize)
    {
      /* radix point is to the right of the limbs, no denominator */
      mp_ptr  num_ptr;

      num_ptr = MPZ_NEWALLOC (mpq_numref (q), fexp);
      MPN_ZERO (num_ptr, fexp - abs_fsize);
      MPN_COPY (num_ptr + fexp - abs_fsize, fptr, abs_fsize);

      SIZ(NUM(q)) = fsize >= 0 ? fexp : -fexp;
      SIZ(DEN(q)) = 1;
      PTR(DEN(q))[0] = 1;
    }
  else
    {
      /* radix point is within or to the left of the limbs, use denominator */
      mp_ptr     num_ptr, den_ptr;
      mp_size_t  den_size;

      den_size = abs_fsize - fexp;
      num_ptr = MPZ_NEWALLOC (mpq_numref (q), abs_fsize);
      den_ptr = MPZ_NEWALLOC (mpq_denref (q), den_size+1);

      if (flow & 1)
        {
          /* no powers of two to strip from numerator */

          MPN_COPY (num_ptr, fptr, abs_fsize);
          MPN_ZERO (den_ptr, den_size);
          den_ptr[den_size] = 1;
        }
      else
        {
          /* right shift numerator, adjust denominator accordingly */
          int  shift;

          den_size--;
          count_trailing_zeros (shift, flow);

          mpn_rshift (num_ptr, fptr, abs_fsize, shift);
          abs_fsize -= (num_ptr[abs_fsize-1] == 0);

          MPN_ZERO (den_ptr, den_size);
          den_ptr[den_size] = GMP_LIMB_HIGHBIT >> (shift-1);
        }

      SIZ(NUM(q)) = fsize >= 0 ? abs_fsize : -abs_fsize;
      SIZ(DEN(q)) = den_size + 1;
    }
}
Ejemplo n.º 14
0
/* Get a limb pointer for writing, previous contents may be
   destroyed. */
mp_limb_t *
mpz_limbs_write (mpz_ptr x, mp_size_t n)
{
  assert (n > 0);
  return MPZ_NEWALLOC (x, n);
}
Ejemplo n.º 15
0
  choke me
#endif

void
mpq_set_d (mpq_ptr dest, double d)
{
  int negative;
  mp_exp_t exp;
  mp_limb_t tp[LIMBS_PER_DOUBLE];
  mp_ptr np, dp;
  mp_size_t nn, dn;
  int c;

  DOUBLE_NAN_INF_ACTION (d,
                         __gmp_invalid_operation (),
                         __gmp_invalid_operation ());

  negative = d < 0;
  d = ABS (d);

  exp = __gmp_extract_double (tp, d);

  /* There are two main version of the conversion.  The `then' arm handles
     numbers with a fractional part, while the `else' arm handles integers.  */
#if LIMBS_PER_DOUBLE == 4
  if (exp <= 1 || (exp == 2 && (tp[0] | tp[1]) != 0))
#endif
#if LIMBS_PER_DOUBLE == 3
  if (exp <= 1 || (exp == 2 && tp[0] != 0))
#endif
#if LIMBS_PER_DOUBLE == 2
  if (exp <= 1)
#endif
    {
      if (d == 0.0)
	{
	  SIZ(NUM(dest)) = 0;
	  SIZ(DEN(dest)) = 1;
	  PTR(DEN(dest))[0] = 1;
	  return;
	}

#if LIMBS_PER_DOUBLE == 4
      np = MPZ_NEWALLOC (NUM(dest), 4);
      if ((tp[0] | tp[1] | tp[2]) == 0)
	np[0] = tp[3], nn = 1;
      else if ((tp[0] | tp[1]) == 0)
	np[1] = tp[3], np[0] = tp[2], nn = 2;
      else if (tp[0] == 0)
	np[2] = tp[3], np[1] = tp[2], np[0] = tp[1], nn = 3;
      else
	np[3] = tp[3], np[2] = tp[2], np[1] = tp[1], np[0] = tp[0], nn = 4;
#endif
#if LIMBS_PER_DOUBLE == 3
      np = MPZ_NEWALLOC (NUM(dest), 3);
      if ((tp[0] | tp[1]) == 0)
	np[0] = tp[2], nn = 1;
      else if (tp[0] == 0)
	np[1] = tp[2], np[0] = tp[1], nn = 2;
      else
	np[2] = tp[2], np[1] = tp[1], np[0] = tp[0], nn = 3;
#endif
#if LIMBS_PER_DOUBLE == 2
      np = MPZ_NEWALLOC (NUM(dest), 2);
      if (tp[0] == 0)
	np[0] = tp[1], nn = 1;
      else
	np[1] = tp[1], np[0] = tp[0], nn = 2;
#endif
      dn = nn + 1 - exp;
      ASSERT (dn > 0); /* -exp >= -1; nn >= 1*/
      dp = MPZ_NEWALLOC (DEN(dest), dn);
      MPN_ZERO (dp, dn - 1);
      dp[dn - 1] = 1;
      count_trailing_zeros (c, np[0] | dp[0]);
      if (c != 0)
	{
	  mpn_rshift (np, np, nn, c);
	  nn -= np[nn - 1] == 0;
	  --dn;
	  dp[dn - 1] = CNST_LIMB(1) << (GMP_LIMB_BITS - c);
	}
      SIZ(DEN(dest)) = dn;
    }
  else
    {
      nn = exp;
      np = MPZ_NEWALLOC (NUM(dest), nn);
      switch (nn)
        {
	default:
	  MPN_ZERO (np, nn - LIMBS_PER_DOUBLE);
	  np += nn - LIMBS_PER_DOUBLE;
	  /* fall through */
#if LIMBS_PER_DOUBLE == 2
	case 2:
	  np[1] = tp[1], np[0] = tp[0];
	  break;
#endif
#if LIMBS_PER_DOUBLE == 3
	case 3:
	  np[2] = tp[2], np[1] = tp[1], np[0] = tp[0];
	  break;
	case 2:
	  np[1] = tp[2], np[0] = tp[1];
	  break;
#endif
#if LIMBS_PER_DOUBLE == 4
	case 4:
	  np[3] = tp[3], np[2] = tp[2], np[1] = tp[1], np[0] = tp[0];
	  break;
	case 3:
	  np[2] = tp[3], np[1] = tp[2], np[0] = tp[1];
	  break;
	case 2:
	  np[1] = tp[3], np[0] = tp[2];
	  break;
#endif
	}
      *PTR(DEN(dest)) = 1;
      SIZ(DEN(dest)) = 1;
    }
  SIZ(NUM(dest)) = negative ? -nn : nn;
}
Ejemplo n.º 16
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;
	  MPZ_NEWALLOC (s, 1)[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;
}
Ejemplo n.º 17
0
void
mpz_powm_sec (mpz_ptr r, mpz_srcptr b, mpz_srcptr e, mpz_srcptr m)
{
  mp_size_t n;
  mp_ptr rp, tp;
  mp_srcptr bp, ep, mp;
  mp_size_t rn, bn, es, en;
  TMP_DECL;

  n = ABSIZ(m);

  mp = PTR(m);

  if (UNLIKELY ((n == 0) || (mp[0] % 2 == 0)))
    DIVIDE_BY_ZERO;

  es = SIZ(e);
  if (UNLIKELY (es <= 0))
    {
      if (es == 0)
	{
	  /* b^0 mod m,  b is anything and m is non-zero.
	     Result is 1 mod m, i.e., 1 or 0 depending on if m = 1.  */
	  SIZ(r) = n != 1 || mp[0] != 1;
	  MPZ_NEWALLOC (r, 1)[0] = 1;
	  return;
	}
      DIVIDE_BY_ZERO;
    }
  en = es;

  bn = ABSIZ(b);

  if (UNLIKELY (bn == 0))
    {
      SIZ(r) = 0;
      return;
    }

  TMP_MARK;
  tp = TMP_ALLOC_LIMBS (n + mpn_sec_powm_itch (bn, en * GMP_NUMB_BITS, n));

  rp = tp;  tp += n;

  bp = PTR(b);
  ep = PTR(e);

  mpn_sec_powm (rp, bp, bn, ep, en * GMP_NUMB_BITS, mp, n, tp);

  rn = n;

  MPN_NORMALIZE (rp, rn);

  if ((ep[0] & 1) && SIZ(b) < 0 && rn != 0)
    {
      mpn_sub (rp, PTR(m), n, rp, rn);
      rn = n;
      MPN_NORMALIZE (rp, rn);
    }

  MPZ_REALLOC (r, rn);
  SIZ(r) = rn;
  MPN_COPY (PTR(r), rp, rn);

  TMP_FREE;
}
Ejemplo n.º 18
0
void
mpz_mfac_uiui (mpz_ptr x, unsigned long n, unsigned long m)
{
  ASSERT (n <= GMP_NUMB_MAX);
  ASSERT (m != 0);

  if ((n < 3) | (n - 3 < m - 1)) { /* (n < 3 || n - 1 <= m || m == 0) */
    PTR (x)[0] = n + (n == 0);
    SIZ (x) = 1;
  } else { /* m < n - 1 < GMP_NUMB_MAX */
    mp_limb_t g, sn;
    mpz_t     t;

    sn = n;
    g = mpn_gcd_1 (&sn, 1, m);
    if (g > 1) { n/=g; m/=g; }

    if (m <= 2) { /* fac or 2fac */
      if (m == 1) {
	if (g > 2) {
	  mpz_init (t);
	  mpz_fac_ui (t, n);
	  sn = n;
	} else {
	  if (g == 2)
	    mpz_2fac_ui (x, n << 1);
	  else
	    mpz_fac_ui (x, n);
	  return;
	}
      } else { /* m == 2 */
	if (g > 1) {
	  mpz_init (t);
	  mpz_2fac_ui (t, n);
	  sn = n / 2 + 1;
	} else {
	  mpz_2fac_ui (x, n);
	  return;
	}
      }
    } else { /* m >= 3, gcd(n,m) = 1 */
      mp_limb_t *factors;
      mp_limb_t prod, max_prod, j;
      TMP_DECL;

      sn = n / m + 1;

      j = 0;
      prod = n;
      n -= m;
      max_prod = GMP_NUMB_MAX / n;

      if (g > 1)
	factors = MPZ_NEWALLOC (x, sn / log_n_max (n) + 2);
      else {
	TMP_MARK;
	factors = TMP_ALLOC_LIMBS (sn / log_n_max (n) + 2);
      }

      for (; n > m; n -= m)
	FACTOR_LIST_STORE (n, prod, max_prod, factors, j);

      factors[j++] = n;
      factors[j++] = prod;

      if (g > 1) {
	mpz_init (t);
	mpz_prodlimbs (t, factors, j);
      } else {
	mpz_prodlimbs (x, factors, j);
	TMP_FREE;
	return;
      }
    }

    {
      mpz_t p;

      mpz_init (p);
      mpz_ui_pow_ui (p, g, sn); /* g^sn */
      mpz_mul (x, p, t);
      mpz_clear (p);
      mpz_clear (t);
    }
  }
}