Пример #1
0
void
mpf_sub (mpf_ptr r, mpf_srcptr u, mpf_srcptr v)
{
  mp_srcptr up, vp;
  mp_ptr rp, tp;
  mp_size_t usize, vsize, rsize;
  mp_size_t prec;
  mp_exp_t exp;
  mp_size_t ediff;
  int negate;
  TMP_DECL;

  usize = u->_mp_size;
  vsize = v->_mp_size;

  /* Handle special cases that don't work in generic code below.  */
  if (usize == 0)
    {
      mpf_neg (r, v);
      return;
    }
  if (vsize == 0)
    {
      if (r != u)
        mpf_set (r, u);
      return;
    }

  /* If signs of U and V are different, perform addition.  */
  if ((usize ^ vsize) < 0)
    {
      __mpf_struct v_negated;
      v_negated._mp_size = -vsize;
      v_negated._mp_exp = v->_mp_exp;
      v_negated._mp_d = v->_mp_d;
      mpf_add (r, u, &v_negated);
      return;
    }

  TMP_MARK;

  /* Signs are now known to be the same.  */
  negate = usize < 0;

  /* Make U be the operand with the largest exponent.  */
  if (u->_mp_exp < v->_mp_exp)
    {
      mpf_srcptr t;
      t = u; u = v; v = t;
      negate ^= 1;
      usize = u->_mp_size;
      vsize = v->_mp_size;
    }

  usize = ABS (usize);
  vsize = ABS (vsize);
  up = u->_mp_d;
  vp = v->_mp_d;
  rp = r->_mp_d;
  prec = r->_mp_prec + 1;
  exp = u->_mp_exp;
  ediff = u->_mp_exp - v->_mp_exp;

  /* If ediff is 0 or 1, we might have a situation where the operands are
     extremely close.  We need to scan the operands from the most significant
     end ignore the initial parts that are equal.  */
  if (ediff <= 1)
    {
      if (ediff == 0)
	{
	  /* Skip leading limbs in U and V that are equal.  */
	  if (up[usize - 1] == vp[vsize - 1])
	    {
	      /* This loop normally exits immediately.  Optimize for that.  */
	      do
		{
		  usize--;
		  vsize--;
		  exp--;

		  if (usize == 0)
		    {
                      /* u cancels high limbs of v, result is rest of v */
		      negate ^= 1;
                    cancellation:
                      /* strip high zeros before truncating to prec */
                      while (vsize != 0 && vp[vsize - 1] == 0)
                        {
                          vsize--;
                          exp--;
                        }
		      if (vsize > prec)
			{
			  vp += vsize - prec;
			  vsize = prec;
			}
                      MPN_COPY_INCR (rp, vp, vsize);
                      rsize = vsize;
                      goto done;
		    }
		  if (vsize == 0)
		    {
                      vp = up;
                      vsize = usize;
                      goto cancellation;
		    }
		}
	      while (up[usize - 1] == vp[vsize - 1]);
	    }

	  if (up[usize - 1] < vp[vsize - 1])
	    {
	      /* For simplicity, swap U and V.  Note that since the loop above
		 wouldn't have exited unless up[usize - 1] and vp[vsize - 1]
		 were non-equal, this if-statement catches all cases where U
		 is smaller than V.  */
	      MPN_SRCPTR_SWAP (up,usize, vp,vsize);
	      negate ^= 1;
	      /* negating ediff not necessary since it is 0.  */
	    }

	  /* Check for
	     x+1 00000000 ...
	      x  ffffffff ... */
	  if (up[usize - 1] != vp[vsize - 1] + 1)
	    goto general_case;
	  usize--;
	  vsize--;
	  exp--;
	}
      else /* ediff == 1 */
	{
	  /* Check for
	     1 00000000 ...
	     0 ffffffff ... */

	  if (up[usize - 1] != 1 || vp[vsize - 1] != GMP_NUMB_MAX
	      || (usize >= 2 && up[usize - 2] != 0))
	    goto general_case;

	  usize--;
	  exp--;
	}

      /* Skip sequences of 00000000/ffffffff */
      while (vsize != 0 && usize != 0 && up[usize - 1] == 0
	     && vp[vsize - 1] == GMP_NUMB_MAX)
	{
	  usize--;
	  vsize--;
	  exp--;
	}

      if (usize == 0)
	{
	  while (vsize != 0 && vp[vsize - 1] == GMP_NUMB_MAX)
	    {
	      vsize--;
	      exp--;
	    }
	}

      if (usize > prec - 1)
	{
	  up += usize - (prec - 1);
	  usize = prec - 1;
	}
      if (vsize > prec - 1)
	{
	  vp += vsize - (prec - 1);
	  vsize = prec - 1;
	}

      tp = (mp_ptr) TMP_ALLOC (prec * BYTES_PER_MP_LIMB);
      {
	mp_limb_t cy_limb;
	if (vsize == 0)
	  {
	    mp_size_t size, i;
	    size = usize;
	    for (i = 0; i < size; i++)
	      tp[i] = up[i];
	    tp[size] = 1;
	    rsize = size + 1;
	    exp++;
	    goto normalize;
	  }
	if (usize == 0)
	  {
	    mp_size_t size, i;
	    size = vsize;
	    for (i = 0; i < size; i++)
	      tp[i] = ~vp[i] & GMP_NUMB_MASK;
	    cy_limb = 1 - mpn_add_1 (tp, tp, vsize, (mp_limb_t) 1);
	    rsize = vsize;
	    if (cy_limb == 0)
	      {
		tp[rsize] = 1;
		rsize++;
		exp++;
	      }
	    goto normalize;
	  }
	if (usize >= vsize)
	  {
	    /* uuuu     */
	    /* vv       */
	    mp_size_t size;
	    size = usize - vsize;
	    MPN_COPY (tp, up, size);
	    cy_limb = mpn_sub_n (tp + size, up + size, vp, vsize);
	    rsize = usize;
	  }
	else /* (usize < vsize) */
	  {
	    /* uuuu     */
	    /* vvvvvvv  */
	    mp_size_t size, i;
	    size = vsize - usize;
	    for (i = 0; i < size; i++)
	      tp[i] = ~vp[i] & GMP_NUMB_MASK;
	    cy_limb = mpn_sub_n (tp + size, up, vp + size, usize);
	    cy_limb+= mpn_sub_1 (tp + size, tp + size, usize, (mp_limb_t) 1);
	    cy_limb-= mpn_add_1 (tp, tp, vsize, (mp_limb_t) 1);
	    rsize = vsize;
	  }
	if (cy_limb == 0)
	  {
	    tp[rsize] = 1;
	    rsize++;
	    exp++;
	  }
	goto normalize;
      }
    }

general_case:
  /* If U extends beyond PREC, ignore the part that does.  */
  if (usize > prec)
    {
      up += usize - prec;
      usize = prec;
    }

  /* If V extends beyond PREC, ignore the part that does.
     Note that this may make vsize negative.  */
  if (vsize + ediff > prec)
    {
      vp += vsize + ediff - prec;
      vsize = prec - ediff;
    }

  /* Allocate temp space for the result.  Allocate
     just vsize + ediff later???  */
  tp = (mp_ptr) TMP_ALLOC (prec * BYTES_PER_MP_LIMB);

  if (ediff >= prec)
    {
      /* V completely cancelled.  */
      if (tp != up)
	MPN_COPY (rp, up, usize);
      rsize = usize;
    }
  else
    {
      /* Locate the least significant non-zero limb in (the needed
	 parts of) U and V, to simplify the code below.  */
      for (;;)
	{
	  if (vsize == 0)
	    {
	      MPN_COPY (rp, up, usize);
	      rsize = usize;
	      goto done;
	    }
	  if (vp[0] != 0)
	    break;
	  vp++, vsize--;
	}
      for (;;)
	{
	  if (usize == 0)
	    {
	      MPN_COPY (rp, vp, vsize);
	      rsize = vsize;
	      negate ^= 1;
	      goto done;
	    }
	  if (up[0] != 0)
	    break;
	  up++, usize--;
	}

      /* uuuu     |  uuuu     |  uuuu     |  uuuu     |  uuuu    */
      /* vvvvvvv  |  vv       |    vvvvv  |    v      |       vv */

      if (usize > ediff)
	{
	  /* U and V partially overlaps.  */
	  if (ediff == 0)
	    {
	      /* Have to compare the leading limbs of u and v
		 to determine whether to compute u - v or v - u.  */
	      if (usize >= vsize)
		{
		  /* uuuu     */
		  /* vv       */
		  mp_size_t size;
		  size = usize - vsize;
		  MPN_COPY (tp, up, size);
		  mpn_sub_n (tp + size, up + size, vp, vsize);
		  rsize = usize;
		}
	      else /* (usize < vsize) */
		{
		  /* uuuu     */
		  /* vvvvvvv  */
		  mp_size_t size, i;
		  size = vsize - usize;
		  tp[0] = -vp[0] & GMP_NUMB_MASK;
		  for (i = 1; i < size; i++)
		    tp[i] = ~vp[i] & GMP_NUMB_MASK;
		  mpn_sub_n (tp + size, up, vp + size, usize);
		  mpn_sub_1 (tp + size, tp + size, usize, (mp_limb_t) 1);
		  rsize = vsize;
		}
	    }
	  else
	    {
	      if (vsize + ediff <= usize)
		{
		  /* uuuu     */
		  /*   v      */
		  mp_size_t size;
		  size = usize - ediff - vsize;
		  MPN_COPY (tp, up, size);
		  mpn_sub (tp + size, up + size, usize - size, vp, vsize);
		  rsize = usize;
		}
	      else
		{
		  /* uuuu     */
		  /*   vvvvv  */
		  mp_size_t size, i;
		  size = vsize + ediff - usize;
		  tp[0] = -vp[0] & GMP_NUMB_MASK;
		  for (i = 1; i < size; i++)
		    tp[i] = ~vp[i] & GMP_NUMB_MASK;
		  mpn_sub (tp + size, up, usize, vp + size, usize - ediff);
		  mpn_sub_1 (tp + size, tp + size, usize, (mp_limb_t) 1);
		  rsize = vsize + ediff;
		}
	    }
	}
      else
	{
	  /* uuuu     */
	  /*      vv  */
	  mp_size_t size, i;
	  size = vsize + ediff - usize;
	  tp[0] = -vp[0] & GMP_NUMB_MASK;
	  for (i = 1; i < vsize; i++)
	    tp[i] = ~vp[i] & GMP_NUMB_MASK;
	  for (i = vsize; i < size; i++)
	    tp[i] = GMP_NUMB_MAX;
	  mpn_sub_1 (tp + size, up, usize, (mp_limb_t) 1);
	  rsize = size + usize;
	}

    normalize:
      /* Full normalize.  Optimize later.  */
      while (rsize != 0 && tp[rsize - 1] == 0)
	{
	  rsize--;
	  exp--;
	}
      MPN_COPY (rp, tp, rsize);
    }

 done:
  r->_mp_size = negate ? -rsize : rsize;
  if (rsize == 0)
    exp = 0;
  r->_mp_exp = exp;
  TMP_FREE;
}
Пример #2
0
mp_limb_t
mpn_mul (mp_ptr prodp,
	 mp_srcptr up, mp_size_t un,
	 mp_srcptr vp, mp_size_t vn)
{
  mp_size_t l, k;
  mp_limb_t c;

  ASSERT (un >= vn);
  ASSERT (vn >= 1);
  ASSERT (! MPN_OVERLAP_P (prodp, un+vn, up, un));
  ASSERT (! MPN_OVERLAP_P (prodp, un+vn, vp, vn));

  if (un == vn)
   {
    if (up == vp)
    {
      mpn_sqr (prodp, up, un);
      return prodp[2 * un - 1];
    }
    else
    {
      mpn_mul_n (prodp, up, vp, un);
      return prodp[2 * un - 1];
    }
   }

  if (vn < MUL_KARATSUBA_THRESHOLD)
    { /* plain schoolbook multiplication */
      if (un <= MUL_BASECASE_MAX_UN)
	mpn_mul_basecase (prodp, up, un, vp, vn);
      else
	{
	  /* We have un >> MUL_BASECASE_MAX_UN > vn.  For better memory
	     locality, split up[] into MUL_BASECASE_MAX_UN pieces and multiply
	     these pieces with the vp[] operand.  After each such partial
	     multiplication (but the last) we copy the most significant vn
	     limbs into a temporary buffer since that part would otherwise be
	     overwritten by the next multiplication.  After the next
	     multiplication, we add it back.  This illustrates the situation:

                                                    -->vn<--
                                                      |  |<------- un ------->|
                                                         _____________________|
                                                        X                    /|
                                                      /XX__________________/  |
                                    _____________________                     |
                                   X                    /                     |
                                 /XX__________________/                       |
               _____________________                                          |
              /                    /                                          |
            /____________________/                                            |
	    ==================================================================

	    The parts marked with X are the parts whose sums are copied into
	    the temporary buffer.  */

	  mp_limb_t tp[MUL_KARATSUBA_THRESHOLD_LIMIT];
	  mp_limb_t cy;
          ASSERT (MUL_KARATSUBA_THRESHOLD <= MUL_KARATSUBA_THRESHOLD_LIMIT);

	  mpn_mul_basecase (prodp, up, MUL_BASECASE_MAX_UN, vp, vn);
	  prodp += MUL_BASECASE_MAX_UN;
	  MPN_COPY (tp, prodp, vn);		/* preserve high triangle */
	  up += MUL_BASECASE_MAX_UN;
	  un -= MUL_BASECASE_MAX_UN;
	  while (un > MUL_BASECASE_MAX_UN)
	    {
	      mpn_mul_basecase (prodp, up, MUL_BASECASE_MAX_UN, vp, vn);
	      cy = mpn_add_n (prodp, prodp, tp, vn); /* add back preserved triangle */
	      mpn_incr_u (prodp + vn, cy);		/* safe? */
	      prodp += MUL_BASECASE_MAX_UN;
	      MPN_COPY (tp, prodp, vn);		/* preserve high triangle */
	      up += MUL_BASECASE_MAX_UN;
	      un -= MUL_BASECASE_MAX_UN;
	    }
	  if (un > vn)
	    {
	      mpn_mul_basecase (prodp, up, un, vp, vn);
	    }
	  else
	    {
	      ASSERT_ALWAYS (un > 0);
	      mpn_mul_basecase (prodp, vp, vn, up, un);
	    }
	  cy = mpn_add_n (prodp, prodp, tp, vn); /* add back preserved triangle */
	  mpn_incr_u (prodp + vn, cy);		/* safe? */
	}
      return prodp[un + vn - 1];
  }

  if (ABOVE_THRESHOLD (un + vn, 2*MUL_FFT_FULL_THRESHOLD)
      && ABOVE_THRESHOLD (3*vn, MUL_FFT_FULL_THRESHOLD))
    {
      mpn_mul_fft_main (prodp, up, un, vp, vn);
      return prodp[un + vn - 1];
    }

  k = (un + 3)/4; // ceil(un/4)

#if GMP_NUMB_BITS == 32
  if ((ABOVE_THRESHOLD (un + vn, 2*MUL_TOOM8H_THRESHOLD)) && (vn>=86) && (5*un <= 11*vn))
#else
  if ((ABOVE_THRESHOLD (un + vn, 2*MUL_TOOM8H_THRESHOLD)) && (vn>=86) && (4*un <= 13*vn))
#endif
  {
      mpn_toom8h_mul(prodp, up, un, vp, vn);
      return prodp[un + vn - 1];
  }
  
  if (ABOVE_THRESHOLD (un + vn, 2*MUL_TOOM4_THRESHOLD))
  {
          if (vn > 3*k)
          {
             mpn_toom4_mul(prodp, up, un, vp, vn);
             return prodp[un + vn - 1];
          } else
          {
             l = (un + 4)/5; // ceil(un/5)
             if ((((vn > 9*k/4) && (un+vn <= 6*MUL_TOOM4_THRESHOLD)) 
                 || ((vn > 2*l) && (un+vn > 6*MUL_TOOM4_THRESHOLD)))
                 && (vn <= 3*l))
             {
                mpn_toom53_mul(prodp, up, un, vp, vn);
                return prodp[un + vn - 1];
             }
          }
  } 
  
  if (ABOVE_THRESHOLD (un + vn, 2*MUL_TOOM3_THRESHOLD) && (vn > k))
  {
          mp_ptr ws;
          TMP_DECL;
          TMP_MARK;

          if (vn < 2*k) // un/2 >= vn > un/4
          {
                  ws = TMP_ALLOC_LIMBS (MPN_TOOM3_MUL_TSIZE(un));
                  mpn_toom42_mul(prodp, up, un, vp, vn, ws);
                  TMP_FREE;
                  return prodp[un + vn - 1];
          }

          l = (un+2)/3; //ceil(u/3)
          if (vn > 2*l) // un >= vn > 2un/3
          {
                  ws = TMP_ALLOC_LIMBS (MPN_TOOM3_MUL_TSIZE(un));
                  mpn_toom3_mul(prodp, up, un, vp, vn, ws);
                  TMP_FREE;
                  return prodp[un + vn - 1];
          } else // 2un/3 >= vn > un/3
          {
                  ws = TMP_ALLOC_LIMBS (MPN_TOOM3_MUL_TSIZE(un));
                  mpn_toom32_mul(prodp, up, un, vp, vn, ws);
                  TMP_FREE;
                  return prodp[un + vn - 1];
          }
  }

  mpn_mul_n (prodp, up, vp, vn);

  if (un != vn)
    { mp_limb_t t;
      mp_ptr ws;
      TMP_DECL;
      TMP_MARK;

      prodp += vn;
      l = vn;
      up += vn;
      un -= vn;

      if (un < vn)
	{
	  /* Swap u's and v's. */
	  MPN_SRCPTR_SWAP (up,un, vp,vn);
	}

      ws = TMP_ALLOC_LIMBS ((vn >= MUL_KARATSUBA_THRESHOLD ? vn : un) + vn);

      t = 0;
      while (vn >= MUL_KARATSUBA_THRESHOLD)
	{
	  mpn_mul_n (ws, up, vp, vn);
	  if (l <= 2*vn)
	    {
	      t += mpn_add_n (prodp, prodp, ws, l);
	      if (l != 2*vn)
		{
		  t = mpn_add_1 (prodp + l, ws + l, 2*vn - l, t);
		  l = 2*vn;
		}
	    }
	  else
	    {
	      c = mpn_add_n (prodp, prodp, ws, 2*vn);
	      t += mpn_add_1 (prodp + 2*vn, prodp + 2*vn, l - 2*vn, c);
	    }
	  prodp += vn;
	  l -= vn;
	  up += vn;
	  un -= vn;
	  if (un < vn)
	    {
	      /* Swap u's and v's. */
	      MPN_SRCPTR_SWAP (up,un, vp,vn);
	    }
		}

      if (vn != 0)
	{
	  mpn_mul_basecase (ws, up, un, vp, vn);
	  if (l <= un + vn)
	    {
	      t += mpn_add_n (prodp, prodp, ws, l);
	      if (l != un + vn)
		t = mpn_add_1 (prodp + l, ws + l, un + vn - l, t);
	    }
	  else
	    {
	      c = mpn_add_n (prodp, prodp, ws, un + vn);
	      t += mpn_add_1 (prodp + un + vn, prodp + un + vn, l - un - vn, c);
	    }
	}

      TMP_FREE;
  }

  return prodp[un + vn - 1];
}
Пример #3
0
unsigned long
mpz_hamdist (mpz_srcptr u, mpz_srcptr v)
{
  mp_srcptr      up, vp;
  mp_size_t      usize, vsize;
  unsigned long  count;

  usize = SIZ(u);
  vsize = SIZ(v);

  up = PTR(u);
  vp = PTR(v);

  if (usize >= 0)
    {
      if (vsize < 0)
        return ~ (unsigned long) 0;

      /* positive/positive */

      if (usize < vsize)
        MPN_SRCPTR_SWAP (up,usize, vp,vsize);

      count = 0;
      if (vsize != 0)
        count = mpn_hamdist (up, vp, vsize);

      usize -= vsize;
      if (usize != 0)
        count += mpn_popcount (up + vsize, usize);

      return count;
    }
  else
    {
      mp_limb_t  ulimb, vlimb;
      mp_size_t  old_vsize, step;

      if (vsize >= 0)
        return ~ (unsigned long) 0;

      /* negative/negative */

      usize = -usize;
      vsize = -vsize;

      /* skip common low zeros */
      for (;;)
        {
          ASSERT (usize > 0);
          ASSERT (vsize > 0);

          usize--;
          vsize--;

          ulimb = *up++;
          vlimb = *vp++;

          if (ulimb != 0)
            break;

          if (vlimb != 0)
            {
              MPN_SRCPTR_SWAP (up,usize, vp,vsize);
              ulimb = vlimb;
              vlimb = 0;
              break;
            }
        }

      /* twos complement first non-zero limbs (ulimb is non-zero, but vlimb
         might be zero) */
      ulimb = -ulimb;
      vlimb = -vlimb;
      popc_limb (count, (ulimb ^ vlimb) & GMP_NUMB_MASK);

      if (vlimb == 0)
        {
          unsigned long  twoscount;

          /* first non-zero of v */
          old_vsize = vsize;
          do
            {
              ASSERT (vsize > 0);
              vsize--;
              vlimb = *vp++;
            }
          while (vlimb == 0);

          /* part of u corresponding to skipped v zeros */
          step = old_vsize - vsize - 1;
          count += step * GMP_NUMB_BITS;
          step = MIN (step, usize);
          if (step != 0)
            {
              count -= mpn_popcount (up, step);
              usize -= step;
              up += step;
            }

          /* First non-zero vlimb as twos complement, xor with ones
             complement ulimb.  Note -v^(~0^u) == (v-1)^u. */
          vlimb--;
          if (usize != 0)
            {
              usize--;
              vlimb ^= *up++;
            }
          popc_limb (twoscount, vlimb);
          count += twoscount;
        }

      /* Overlapping part of u and v, if any.  Ones complement both, so just
         plain hamdist. */
      step = MIN (usize, vsize);
      if (step != 0)
        {
          count += mpn_hamdist (up, vp, step);
          usize -= step;
          vsize -= step;
          up += step;
          vp += step;
        }

      /* Remaining high part of u or v, if any, ones complement but xor
         against all ones in the other, so plain popcount. */
      if (usize != 0)
        {
        remaining:
          count += mpn_popcount (up, usize);
        }
      else if (vsize != 0)
        {
          up = vp;
          usize = vsize;
          goto remaining;
        }
      return count;
    }
}
Пример #4
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;
  }
}
Пример #5
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;
}
Пример #6
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;
    }
}