Пример #1
0
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;
}
Пример #2
0
void
check_one (mpz_srcptr a, mpz_srcptr c, mpz_srcptr d, int want)
{
  int   got;
  int   swap;

  for (swap = 0; swap <= 1; swap++)
    {
      got = (mpz_congruent_p (a, c, d) != 0);
      if (want != got)
        {
          printf ("mpz_congruent_p wrong\n");
          printf ("   expected %d got %d\n", want, got);
          mpz_trace ("   a", a);
          mpz_trace ("   c", c);
          mpz_trace ("   d", d);
          mp_trace_base = -16;
          mpz_trace ("   a", a);
          mpz_trace ("   c", c);
          mpz_trace ("   d", d);
          abort ();
        }

      if (mpz_fits_ulong_p (c) && mpz_fits_ulong_p (d))
        {
          unsigned long  uc = mpz_get_ui (c);
          unsigned long  ud = mpz_get_ui (d);
          got = (mpz_congruent_ui_p (a, uc, ud) != 0);
          if (want != got)
            {
              printf    ("mpz_congruent_ui_p wrong\n");
              printf    ("   expected %d got %d\n", want, got);
              mpz_trace ("   a", a);
              printf    ("   c=%lu\n", uc);
              printf    ("   d=%lu\n", ud);
              mp_trace_base = -16;
              mpz_trace ("   a", a);
              printf    ("   c=0x%lX\n", uc);
              printf    ("   d=0x%lX\n", ud);
              abort ();
            }
        }

      MPZ_SRCPTR_SWAP (a, c);
    }
}
Пример #3
0
void
mpz_mul (mpz_ptr w, mpz_srcptr u, mpz_srcptr v)
{
  mp_size_t usize;
  mp_size_t vsize;
  mp_size_t wsize;
  mp_size_t sign_product;
  mp_ptr up, vp;
  mp_ptr wp;
  mp_ptr free_me;
  size_t free_me_size;
  mp_limb_t cy_limb;
  TMP_DECL;

  usize = SIZ (u);
  vsize = SIZ (v);
  sign_product = usize ^ vsize;
  usize = ABS (usize);
  vsize = ABS (vsize);

  if (usize < vsize)
    {
      MPZ_SRCPTR_SWAP (u, v);
      MP_SIZE_T_SWAP (usize, vsize);
    }

  if (vsize == 0)
    {
      SIZ (w) = 0;
      return;
    }

#if HAVE_NATIVE_mpn_mul_2
  if (vsize <= 2)
    {
      wp = MPZ_REALLOC (w, usize+vsize);
      if (vsize == 1)
	cy_limb = mpn_mul_1 (wp, PTR (u), usize, PTR (v)[0]);
      else
	{
	  cy_limb = mpn_mul_2 (wp, PTR (u), usize, PTR (v));
	  usize++;
	}
      wp[usize] = cy_limb;
      usize += (cy_limb != 0);
      SIZ (w) = (sign_product >= 0 ? usize : -usize);
      return;
    }
#else
  if (vsize == 1)
    {
      wp = MPZ_REALLOC (w, usize+1);
      cy_limb = mpn_mul_1 (wp, PTR (u), usize, PTR (v)[0]);
      wp[usize] = cy_limb;
      usize += (cy_limb != 0);
      SIZ (w) = (sign_product >= 0 ? usize : -usize);
      return;
    }
#endif

  TMP_MARK;
  free_me = NULL;
  up = PTR (u);
  vp = PTR (v);
  wp = PTR (w);

  /* Ensure W has space enough to store the result.  */
  wsize = usize + vsize;
  if (ALLOC (w) < wsize)
    {
      if (wp == up || wp == vp)
	{
	  free_me = wp;
	  free_me_size = ALLOC (w);
	}
      else
	(*__gmp_free_func) (wp, (size_t) ALLOC (w) * GMP_LIMB_BYTES);

      ALLOC (w) = wsize;
      wp = __GMP_ALLOCATE_FUNC_LIMBS (wsize);
      PTR (w) = wp;
    }
  else
    {
      /* Make U and V not overlap with W.  */
      if (wp == up)
	{
	  /* W and U are identical.  Allocate temporary space for U.  */
	  up = TMP_ALLOC_LIMBS (usize);
	  /* Is V identical too?  Keep it identical with U.  */
	  if (wp == vp)
	    vp = up;
	  /* Copy to the temporary space.  */
	  MPN_COPY (up, wp, usize);
	}
      else if (wp == vp)
	{
	  /* W and V are identical.  Allocate temporary space for V.  */
	  vp = TMP_ALLOC_LIMBS (vsize);
	  /* Copy to the temporary space.  */
	  MPN_COPY (vp, wp, vsize);
	}
    }

  if (up == vp)
    {
      mpn_sqr (wp, up, usize);
      cy_limb = wp[wsize - 1];
    }
  else
    {
      cy_limb = mpn_mul (wp, up, usize, vp, vsize);
    }

  wsize -= cy_limb == 0;

  SIZ (w) = sign_product < 0 ? -wsize : wsize;
  if (free_me != NULL)
    (*__gmp_free_func) (free_me, free_me_size * GMP_LIMB_BYTES);
  TMP_FREE;
}
Пример #4
0
int
mpz_congruent_2exp_p (mpz_srcptr a, mpz_srcptr c, mp_bitcnt_t d)
{
  mp_size_t      i, dlimbs;
  unsigned       dbits;
  mp_ptr         ap, cp;
  mp_limb_t      dmask, alimb, climb, sum;
  mp_size_t      asize_signed, csize_signed, asize, csize;

  if (ABSIZ(a) < ABSIZ(c))
    MPZ_SRCPTR_SWAP (a, c);

  dlimbs = d / GMP_NUMB_BITS;
  dbits = d % GMP_NUMB_BITS;
  dmask = (CNST_LIMB(1) << dbits) - 1;

  ap = PTR(a);
  cp = PTR(c);

  asize_signed = SIZ(a);
  asize = ABS(asize_signed);

  csize_signed = SIZ(c);
  csize = ABS(csize_signed);

  if (csize_signed == 0)
    goto a_zeros;

  if ((asize_signed ^ csize_signed) >= 0)
    {
      /* same signs, direct comparison */

      /* a==c for limbs in common */
      if (mpn_cmp (ap, cp, MIN (csize, dlimbs)) != 0)
        return 0;

      /* if that's all of dlimbs, then a==c for remaining bits */
      if (csize > dlimbs)
        return ((ap[dlimbs]-cp[dlimbs]) & dmask) == 0;

    a_zeros:
      /* a remains, need all zero bits */

      /* if d covers all of a and c, then must be exactly equal */
      if (asize <= dlimbs)
        return asize == csize;

      /* whole limbs zero */
      for (i = csize; i < dlimbs; i++)
        if (ap[i] != 0)
          return 0;

      /* partial limb zero */
      return (ap[dlimbs] & dmask) == 0;
    }
  else
    {
      /* different signs, negated comparison */

      /* common low zero limbs, stopping at first non-zeros, which must
         match twos complement */
      i = 0;
      for (;;)
        {
          ASSERT (i < csize);  /* always have a non-zero limb on c */
          alimb = ap[i];
          climb = cp[i];
          sum = (alimb + climb) & GMP_NUMB_MASK;

          if (i >= dlimbs)
            return (sum & dmask) == 0;
          i++;

          /* require both zero, or first non-zeros as twos-complements */
          if (sum != 0)
            return 0;

          if (alimb != 0)
            break;
        }

      /* further limbs matching as ones-complement */
      for (;;)
        {
          if (i >= csize)
            break;

          alimb = ap[i];
          climb = cp[i];
          sum = (alimb + climb + 1) & GMP_NUMB_MASK;

          if (i >= dlimbs)
            return (sum & dmask) == 0;

          if (sum != 0)
            return 0;

          i++;
        }

      /* no more c, so require all 1 bits in a */

      if (asize < dlimbs)
        return 0;   /* not enough a */

      /* whole limbs */
      for ( ; i < dlimbs; i++)
        if (ap[i] != GMP_NUMB_MAX)
          return 0;

      /* if only whole limbs, no further fetches from a */
      if (dbits == 0)
        return 1;

      /* need enough a */
      if (asize == dlimbs)
        return 0;

      return ((ap[dlimbs]+1) & dmask) == 0;
    }
}
Пример #5
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;
}
Пример #6
0
REGPARM_ATTR (1) static void
mpz_aorsmul (mpz_ptr w, mpz_srcptr x, mpz_srcptr y, mp_size_t sub)
{
    mp_size_t  xsize, ysize, tsize, wsize, wsize_signed;
    mp_ptr     wp, tp;
    mp_limb_t  c, high;
    TMP_DECL;

    /* w unaffected if x==0 or y==0 */
    xsize = SIZ(x);
    ysize = SIZ(y);
    if (xsize == 0 || ysize == 0)
        return;

    /* make x the bigger of the two */
    if (ABS(ysize) > ABS(xsize))
    {
        MPZ_SRCPTR_SWAP (x, y);
        MP_SIZE_T_SWAP (xsize, ysize);
    }

    sub ^= ysize;
    ysize = ABS(ysize);

    /* use mpn_addmul_1/mpn_submul_1 if possible */
    if (ysize == 1)
    {
        mpz_aorsmul_1 (w, x, PTR(y)[0], sub);
        return;
    }

    sub ^= xsize;
    xsize = ABS(xsize);

    wsize_signed = SIZ(w);
    sub ^= wsize_signed;
    wsize = ABS(wsize_signed);

    tsize = xsize + ysize;
    wp = MPZ_REALLOC (w, MAX (wsize, tsize) + 1);

    if (wsize_signed == 0)
    {
        /* Nothing to add to, just set w=x*y.  No w==x or w==y overlap here,
        since we know x,y!=0 but w==0.  */
        high = mpn_mul (wp, PTR(x),xsize, PTR(y),ysize);
        tsize -= (high == 0);
        SIZ(w) = (sub >= 0 ? tsize : -tsize);
        return;
    }

    TMP_MARK;
    tp = TMP_ALLOC_LIMBS (tsize);

    high = mpn_mul (tp, PTR(x),xsize, PTR(y),ysize);
    tsize -= (high == 0);
    ASSERT (tp[tsize-1] != 0);
    if (sub >= 0)
    {
        mp_srcptr up    = wp;
        mp_size_t usize = wsize;

        if (usize < tsize)
        {
            up	= tp;
            usize = tsize;
            tp	= wp;
            tsize = wsize;

            wsize = usize;
        }

        c = mpn_add (wp, up,usize, tp,tsize);
        wp[wsize] = c;
        wsize += (c != 0);
    }
    else
    {
        mp_srcptr up    = wp;
        mp_size_t usize = wsize;

        if (mpn_cmp_twosizes_lt (up,usize, tp,tsize))
        {
            up	= tp;
            usize = tsize;
            tp	= wp;
            tsize = wsize;

            wsize = usize;
            wsize_signed = -wsize_signed;
        }

        ASSERT_NOCARRY (mpn_sub (wp, up,usize, tp,tsize));
        wsize = usize;
        MPN_NORMALIZE (wp, wsize);
    }

    SIZ(w) = (wsize_signed >= 0 ? wsize : -wsize);

    TMP_FREE;
}
Пример #7
0
int
mpz_congruent_p (mpz_srcptr a, mpz_srcptr c, mpz_srcptr d)
{
  mp_size_t  asize, csize, dsize, sign;
  mp_srcptr  ap, cp, dp;
  mp_ptr     xp;
  mp_limb_t  alow, clow, dlow, dmask, r;
  int        result;
  TMP_DECL;

  dsize = SIZ(d);
  if (UNLIKELY (dsize == 0))
    return (mpz_cmp (a, c) == 0);

  dsize = ABS(dsize);
  dp = PTR(d);

  if (ABSIZ(a) < ABSIZ(c))
    MPZ_SRCPTR_SWAP (a, c);

  asize = SIZ(a);
  csize = SIZ(c);
  sign = (asize ^ csize);

  asize = ABS(asize);
  ap = PTR(a);

  if (csize == 0)
    return mpn_divisible_p (ap, asize, dp, dsize);

  csize = ABS(csize);
  cp = PTR(c);

  alow = ap[0];
  clow = cp[0];
  dlow = dp[0];

  /* Check a==c mod low zero bits of dlow.  This might catch a few cases of
     a!=c quickly, and it helps the csize==1 special cases below.  */
  dmask = LOW_ZEROS_MASK (dlow) & GMP_NUMB_MASK;
  alow = (sign >= 0 ? alow : -alow);
  if (((alow-clow) & dmask) != 0)
    return 0;

  if (csize == 1)
    {
      if (dsize == 1)
	{
	cong_1:
	  if (sign < 0)
	    NEG_MOD (clow, clow, dlow);

	  if (ABOVE_THRESHOLD (asize, BMOD_1_TO_MOD_1_THRESHOLD))
	    {
	      r = mpn_mod_1 (ap, asize, dlow);
	      if (clow < dlow)
		return r == clow;
	      else
		return r == (clow % dlow);
	    }

	  if ((dlow & 1) == 0)
	    {
	      /* Strip low zero bits to get odd d required by modexact.  If
		 d==e*2^n then a==c mod d if and only if both a==c mod e and
		 a==c mod 2^n, the latter having been done above.  */
	      unsigned	twos;
	      count_trailing_zeros (twos, dlow);
	      dlow >>= twos;
	    }

	  r = mpn_modexact_1c_odd (ap, asize, dlow, clow);
	  return r == 0 || r == dlow;
	}
Пример #8
0
void
mpz_xor (mpz_ptr res, mpz_srcptr op1, mpz_srcptr op2)
{
  mp_srcptr op1_ptr, op2_ptr;
  mp_size_t op1_size, op2_size;
  mp_ptr res_ptr;
  mp_size_t res_size, res_alloc;
  TMP_DECL;

  TMP_MARK;
  op1_size = SIZ(op1);
  op2_size = SIZ(op2);

  op1_ptr = PTR(op1);
  op2_ptr = PTR(op2);
  res_ptr = PTR(res);

  if (op1_size >= 0)
    {
      if (op2_size >= 0)
	{
	  if (op1_size >= op2_size)
	    {
	      if (ALLOC(res) < op1_size)
		{
		  _mpz_realloc (res, op1_size);
		  /* No overlapping possible: op1_ptr = PTR(op1); */
		  op2_ptr = PTR(op2);
		  res_ptr = PTR(res);
		}

	      if (res_ptr != op1_ptr)
		MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size,
			  op1_size - op2_size);
	      if (LIKELY (op2_size != 0))
		mpn_xor_n (res_ptr, op1_ptr, op2_ptr, op2_size);
	      res_size = op1_size;
	    }
	  else
	    {
	      if (ALLOC(res) < op2_size)
		{
		  _mpz_realloc (res, op2_size);
		  op1_ptr = PTR(op1);
		  /* No overlapping possible: op2_ptr = PTR(op2); */
		  res_ptr = PTR(res);
		}

	      if (res_ptr != op2_ptr)
		MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size,
			  op2_size - op1_size);
	      if (LIKELY (op1_size != 0))
		mpn_xor_n (res_ptr, op1_ptr, op2_ptr, op1_size);
	      res_size = op2_size;
	    }

	  MPN_NORMALIZE (res_ptr, res_size);
	  SIZ(res) = res_size;
	  return;
	}
      else /* op2_size < 0 */
	{
	  /* Fall through to the code at the end of the function.  */
	}
    }
  else
    {
      if (op2_size < 0)
	{
	  mp_ptr opx, opy;

	  /* Both operands are negative, the result will be positive.
	      (-OP1) ^ (-OP2) =
	     = ~(OP1 - 1) ^ ~(OP2 - 1) =
	     = (OP1 - 1) ^ (OP2 - 1)  */

	  op1_size = -op1_size;
	  op2_size = -op2_size;

	  /* Possible optimization: Decrease mpn_sub precision,
	     as we won't use the entire res of both.  */
	  TMP_ALLOC_LIMBS_2 (opx, op1_size, opy, op2_size);
	  mpn_sub_1 (opx, op1_ptr, op1_size, (mp_limb_t) 1);
	  op1_ptr = opx;

	  mpn_sub_1 (opy, op2_ptr, op2_size, (mp_limb_t) 1);
	  op2_ptr = opy;

	  if (op1_size > op2_size)
	    MPN_SRCPTR_SWAP (op1_ptr,op1_size, op2_ptr,op2_size);

	  res_alloc = op2_size;
	  res_ptr = MPZ_REALLOC (res, res_alloc);

	  MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size,
		    op2_size - op1_size);
	  mpn_xor_n (res_ptr, op1_ptr, op2_ptr, op1_size);
	  res_size = op2_size;

	  MPN_NORMALIZE (res_ptr, res_size);
	  SIZ(res) = res_size;
	  TMP_FREE;
	  return;
	}
      else
	{
	  /* We should compute -OP1 ^ OP2.  Swap OP1 and OP2 and fall
	     through to the code that handles OP1 ^ -OP2.  */
	  MPZ_SRCPTR_SWAP (op1, op2);
	  MPN_SRCPTR_SWAP (op1_ptr,op1_size, op2_ptr,op2_size);
	}
    }

  {
    mp_ptr opx;
    mp_limb_t cy;

    /* Operand 2 negative, so will be the result.
       -(OP1 ^ (-OP2)) = -(OP1 ^ ~(OP2 - 1)) =
       = ~(OP1 ^ ~(OP2 - 1)) + 1 =
       = (OP1 ^ (OP2 - 1)) + 1      */

    op2_size = -op2_size;

    opx = TMP_ALLOC_LIMBS (op2_size);
    mpn_sub_1 (opx, op2_ptr, op2_size, (mp_limb_t) 1);
    op2_ptr = opx;

    res_alloc = MAX (op1_size, op2_size) + 1;
    if (ALLOC(res) < res_alloc)
      {
	_mpz_realloc (res, res_alloc);
	op1_ptr = PTR(op1);
	/* op2_ptr points to temporary space.  */
	res_ptr = PTR(res);
      }

    if (op1_size > op2_size)
      {
	MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size, op1_size - op2_size);
	mpn_xor_n (res_ptr, op1_ptr, op2_ptr, op2_size);
	res_size = op1_size;
      }
    else
      {
	MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size, op2_size - op1_size);
	if (LIKELY (op1_size != 0))
	  mpn_xor_n (res_ptr, op1_ptr, op2_ptr, op1_size);
	res_size = op2_size;
      }

    cy = mpn_add_1 (res_ptr, res_ptr, res_size, (mp_limb_t) 1);
    res_ptr[res_size] = cy;
    res_size += (cy != 0);

    MPN_NORMALIZE (res_ptr, res_size);
    SIZ(res) = -res_size;
    TMP_FREE;
  }
}
Пример #9
0
void
mpz_ior (mpz_ptr res, mpz_srcptr op1, mpz_srcptr op2)
{
  mp_srcptr op1_ptr, op2_ptr;
  mp_size_t op1_size, op2_size;
  mp_ptr res_ptr;
  mp_size_t res_size;
  mp_size_t i;
  TMP_DECL;

  TMP_MARK;
  op1_size = op1->_mp_size;
  op2_size = op2->_mp_size;

  op1_ptr = op1->_mp_d;
  op2_ptr = op2->_mp_d;
  res_ptr = res->_mp_d;

  if (op1_size >= 0)
    {
      if (op2_size >= 0)
	{
	  if (op1_size >= op2_size)
	    {
	      if (res->_mp_alloc < op1_size)
		{
		  _mpz_realloc (res, op1_size);
		  op1_ptr = op1->_mp_d;
		  op2_ptr = op2->_mp_d;
		  res_ptr = res->_mp_d;
		}

	      if (res_ptr != op1_ptr)
		MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size,
			  op1_size - op2_size);
	      for (i = op2_size - 1; i >= 0; i--)
		res_ptr[i] = op1_ptr[i] | op2_ptr[i];
	      res_size = op1_size;
	    }
	  else
	    {
	      if (res->_mp_alloc < op2_size)
		{
		  _mpz_realloc (res, op2_size);
		  op1_ptr = op1->_mp_d;
		  op2_ptr = op2->_mp_d;
		  res_ptr = res->_mp_d;
		}

	      if (res_ptr != op2_ptr)
		MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size,
			  op2_size - op1_size);
	      for (i = op1_size - 1; i >= 0; i--)
		res_ptr[i] = op1_ptr[i] | op2_ptr[i];
	      res_size = op2_size;
	    }

	  res->_mp_size = res_size;
	  return;
	}
      else /* op2_size < 0 */
	{
	  /* Fall through to the code at the end of the function.  */
	}
    }
  else
    {
      if (op2_size < 0)
	{
	  mp_ptr opx;
	  mp_limb_t cy;

	  /* Both operands are negative, so will be the result.
	     -((-OP1) | (-OP2)) = -(~(OP1 - 1) | ~(OP2 - 1)) =
	     = ~(~(OP1 - 1) | ~(OP2 - 1)) + 1 =
	     = ((OP1 - 1) & (OP2 - 1)) + 1      */

	  op1_size = -op1_size;
	  op2_size = -op2_size;

	  res_size = MIN (op1_size, op2_size);

	  /* Possible optimization: Decrease mpn_sub precision,
	     as we won't use the entire res of both.  */
	  opx = (mp_ptr) TMP_ALLOC (res_size * BYTES_PER_MP_LIMB);
	  mpn_sub_1 (opx, op1_ptr, res_size, (mp_limb_t) 1);
	  op1_ptr = opx;

	  opx = (mp_ptr) TMP_ALLOC (res_size * BYTES_PER_MP_LIMB);
	  mpn_sub_1 (opx, op2_ptr, res_size, (mp_limb_t) 1);
	  op2_ptr = opx;

	  if (res->_mp_alloc < res_size)
	    {
	      _mpz_realloc (res, res_size);
	      res_ptr = res->_mp_d;
	      /* Don't re-read OP1_PTR and OP2_PTR.  They point to
		 temporary space--never to the space RES->_mp_d used
		 to point to before reallocation.  */
	    }

	  /* First loop finds the size of the result.  */
	  for (i = res_size - 1; i >= 0; i--)
	    if ((op1_ptr[i] & op2_ptr[i]) != 0)
	      break;
	  res_size = i + 1;

	  if (res_size != 0)
	    {
	      /* Second loop computes the real result.  */
	      for (i = res_size - 1; i >= 0; i--)
		res_ptr[i] = op1_ptr[i] & op2_ptr[i];

	      cy = mpn_add_1 (res_ptr, res_ptr, res_size, (mp_limb_t) 1);
	      if (cy)
		{
		  res_ptr[res_size] = cy;
		  res_size++;
		}
	    }
	  else
	    {
	      res_ptr[0] = 1;
	      res_size = 1;
	    }

	  res->_mp_size = -res_size;
	  TMP_FREE;
	  return;
	}
      else
	{
	  /* We should compute -OP1 | OP2.  Swap OP1 and OP2 and fall
	     through to the code that handles OP1 | -OP2.  */
          MPZ_SRCPTR_SWAP (op1, op2);
          MPN_SRCPTR_SWAP (op1_ptr,op1_size, op2_ptr,op2_size);
	}
    }

  {
    mp_ptr opx;
    mp_limb_t cy;
    mp_size_t res_alloc;
    mp_size_t count;

    /* Operand 2 negative, so will be the result.
       -(OP1 | (-OP2)) = -(OP1 | ~(OP2 - 1)) =
       = ~(OP1 | ~(OP2 - 1)) + 1 =
       = (~OP1 & (OP2 - 1)) + 1      */

    op2_size = -op2_size;

    res_alloc = op2_size;

    opx = (mp_ptr) TMP_ALLOC (op2_size * BYTES_PER_MP_LIMB);
    mpn_sub_1 (opx, op2_ptr, op2_size, (mp_limb_t) 1);
    op2_ptr = opx;
    op2_size -= op2_ptr[op2_size - 1] == 0;

    if (res->_mp_alloc < res_alloc)
      {
	_mpz_realloc (res, res_alloc);
	op1_ptr = op1->_mp_d;
	res_ptr = res->_mp_d;
	/* Don't re-read OP2_PTR.  It points to temporary space--never
	   to the space RES->_mp_d used to point to before reallocation.  */
      }

    if (op1_size >= op2_size)
      {
	/* We can just ignore the part of OP1 that stretches above OP2,
	   because the result limbs are zero there.  */

	/* First loop finds the size of the result.  */
	for (i = op2_size - 1; i >= 0; i--)
	  if ((~op1_ptr[i] & op2_ptr[i]) != 0)
	    break;
	res_size = i + 1;
	count = res_size;
      }
    else
      {
	res_size = op2_size;

	/* Copy the part of OP2 that stretches above OP1, to RES.  */
	MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size, op2_size - op1_size);
	count = op1_size;
      }

    if (res_size != 0)
      {
	/* Second loop computes the real result.  */
	for (i = count - 1; i >= 0; i--)
	  res_ptr[i] = ~op1_ptr[i] & op2_ptr[i];

	cy = mpn_add_1 (res_ptr, res_ptr, res_size, (mp_limb_t) 1);
	if (cy)
	  {
	    res_ptr[res_size] = cy;
	    res_size++;
	  }
      }
    else
      {
	res_ptr[0] = 1;
	res_size = 1;
      }

    res->_mp_size = -res_size;
  }
  TMP_FREE;
}
Пример #10
0
void
mpz_xor (mpz_ptr res, mpz_srcptr op1, mpz_srcptr op2)
{
    mp_srcptr op1_ptr, op2_ptr;
    mp_size_t op1_size, op2_size;
    mp_ptr res_ptr;
    mp_size_t res_size, res_alloc;
    mp_size_t i;
    TMP_DECL;

    TMP_MARK;
    op1_size = op1->_mp_size;
    op2_size = op2->_mp_size;

    op1_ptr = op1->_mp_d;
    op2_ptr = op2->_mp_d;
    res_ptr = res->_mp_d;

    if (op1_size >= 0)
    {
        if (op2_size >= 0)
        {
            if (op1_size >= op2_size)
            {
                if (res->_mp_alloc < op1_size)
                {
                    _mpz_realloc (res, op1_size);
                    op1_ptr = op1->_mp_d;
                    op2_ptr = op2->_mp_d;
                    res_ptr = res->_mp_d;
                }

                if (res_ptr != op1_ptr)
                    MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size,
                              op1_size - op2_size);
                for (i = op2_size - 1; i >= 0; i--)
                    res_ptr[i] = op1_ptr[i] ^ op2_ptr[i];
                res_size = op1_size;
            }
            else
            {
                if (res->_mp_alloc < op2_size)
                {
                    _mpz_realloc (res, op2_size);
                    op1_ptr = op1->_mp_d;
                    op2_ptr = op2->_mp_d;
                    res_ptr = res->_mp_d;
                }

                if (res_ptr != op2_ptr)
                    MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size,
                              op2_size - op1_size);
                for (i = op1_size - 1; i >= 0; i--)
                    res_ptr[i] = op1_ptr[i] ^ op2_ptr[i];
                res_size = op2_size;
            }

            MPN_NORMALIZE (res_ptr, res_size);
            res->_mp_size = res_size;
            return;
        }
        else /* op2_size < 0 */
        {
            /* Fall through to the code at the end of the function.  */
        }
    }
    else
    {
        if (op2_size < 0)
        {
            mp_ptr opx;

            /* Both operands are negative, the result will be positive.
                (-OP1) ^ (-OP2) =
               = ~(OP1 - 1) ^ ~(OP2 - 1) =
               = (OP1 - 1) ^ (OP2 - 1)  */

            op1_size = -op1_size;
            op2_size = -op2_size;

            /* Possible optimization: Decrease mpn_sub precision,
               as we won't use the entire res of both.  */
            opx = (mp_ptr) TMP_ALLOC (op1_size * BYTES_PER_MP_LIMB);
            mpn_sub_1 (opx, op1_ptr, op1_size, (mp_limb_t) 1);
            op1_ptr = opx;

            opx = (mp_ptr) TMP_ALLOC (op2_size * BYTES_PER_MP_LIMB);
            mpn_sub_1 (opx, op2_ptr, op2_size, (mp_limb_t) 1);
            op2_ptr = opx;

            res_alloc = MAX (op1_size, op2_size);
            if (res->_mp_alloc < res_alloc)
            {
                _mpz_realloc (res, res_alloc);
                res_ptr = res->_mp_d;
                /* Don't re-read OP1_PTR and OP2_PTR.  They point to
                temporary space--never to the space RES->_mp_d used
                 to point to before reallocation.  */
            }

            if (op1_size > op2_size)
            {
                MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size,
                          op1_size - op2_size);
                for (i = op2_size - 1; i >= 0; i--)
                    res_ptr[i] = op1_ptr[i] ^ op2_ptr[i];
                res_size = op1_size;
            }
            else
            {
                MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size,
                          op2_size - op1_size);
                for (i = op1_size - 1; i >= 0; i--)
                    res_ptr[i] = op1_ptr[i] ^ op2_ptr[i];
                res_size = op2_size;
            }

            MPN_NORMALIZE (res_ptr, res_size);
            res->_mp_size = res_size;
            TMP_FREE;
            return;
        }
        else
        {
            /* We should compute -OP1 ^ OP2.  Swap OP1 and OP2 and fall
               through to the code that handles OP1 ^ -OP2.  */
            MPZ_SRCPTR_SWAP (op1, op2);
            MPN_SRCPTR_SWAP (op1_ptr,op1_size, op2_ptr,op2_size);
        }
    }

    {
        mp_ptr opx;
        mp_limb_t cy;

        /* Operand 2 negative, so will be the result.
           -(OP1 ^ (-OP2)) = -(OP1 ^ ~(OP2 - 1)) =
           = ~(OP1 ^ ~(OP2 - 1)) + 1 =
           = (OP1 ^ (OP2 - 1)) + 1      */

        op2_size = -op2_size;

        opx = (mp_ptr) TMP_ALLOC (op2_size * BYTES_PER_MP_LIMB);
        mpn_sub_1 (opx, op2_ptr, op2_size, (mp_limb_t) 1);
        op2_ptr = opx;

        res_alloc = MAX (op1_size, op2_size) + 1;
        if (res->_mp_alloc < res_alloc)
        {
            _mpz_realloc (res, res_alloc);
            op1_ptr = op1->_mp_d;
            res_ptr = res->_mp_d;
            /* Don't re-read OP2_PTR.  It points to temporary space--never
               to the space RES->_mp_d used to point to before reallocation.  */
        }

        if (op1_size > op2_size)
        {
            MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size, op1_size - op2_size);
            for (i = op2_size - 1; i >= 0; i--)
                res_ptr[i] = op1_ptr[i] ^ op2_ptr[i];
            res_size = op1_size;
        }
        else
        {
            MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size, op2_size - op1_size);
            for (i = op1_size - 1; i >= 0; i--)
                res_ptr[i] = op1_ptr[i] ^ op2_ptr[i];
            res_size = op2_size;
        }

        cy = mpn_add_1 (res_ptr, res_ptr, res_size, (mp_limb_t) 1);
        if (cy)
        {
            res_ptr[res_size] = cy;
            res_size++;
        }

        MPN_NORMALIZE (res_ptr, res_size);
        res->_mp_size = -res_size;
        TMP_FREE;
    }
}