Ejemplo n.º 1
0
  /**
   * This method is used for division of an n word dividend by a one word divisor. The quotient is
   * placed into quotient. The one word divisor is specified by divisor. The value of this
   * MutableBigInteger is the dividend at invocation but is replaced by the remainder.
   *
   * <p>NOTE: The value of this MutableBigInteger is modified by this method.
   */
  void divideOneWord(int divisor, MutableBigInteger quotient) {
    long divLong = divisor & LONG_MASK;

    // Special case of one word dividend
    if (intLen == 1) {
      long remValue = value[offset] & LONG_MASK;
      quotient.value[0] = (int) (remValue / divLong);
      quotient.intLen = (quotient.value[0] == 0) ? 0 : 1;
      quotient.offset = 0;

      value[0] = (int) (remValue - (quotient.value[0] * divLong));
      offset = 0;
      intLen = (value[0] == 0) ? 0 : 1;

      return;
    }

    if (quotient.value.length < intLen) quotient.value = new int[intLen];
    quotient.offset = 0;
    quotient.intLen = intLen;

    // Normalize the divisor
    int shift = 32 - BigInteger.bitLen(divisor);

    int rem = value[offset];
    long remLong = rem & LONG_MASK;
    if (remLong < divLong) {
      quotient.value[0] = 0;
    } else {
      quotient.value[0] = (int) (remLong / divLong);
      rem = (int) (remLong - (quotient.value[0] * divLong));
      remLong = rem & LONG_MASK;
    }

    int xlen = intLen;
    int[] qWord = new int[2];
    while (--xlen > 0) {
      long dividendEstimate = (remLong << 32) | (value[offset + intLen - xlen] & LONG_MASK);
      if (dividendEstimate >= 0) {
        qWord[0] = (int) (dividendEstimate / divLong);
        qWord[1] = (int) (dividendEstimate - (qWord[0] * divLong));
      } else {
        divWord(qWord, dividendEstimate, divisor);
      }
      quotient.value[intLen - xlen] = (int) qWord[0];
      rem = (int) qWord[1];
      remLong = rem & LONG_MASK;
    }

    // Unnormalize
    if (shift > 0) value[0] = rem %= divisor;
    else value[0] = rem;
    intLen = (value[0] == 0) ? 0 : 1;

    quotient.normalize();
  }
Ejemplo n.º 2
0
 /** Right shift this MutableBigInteger n bits. The MutableBigInteger is left in normal form. */
 void rightShift(int n) {
   if (intLen == 0) return;
   int nInts = n >>> 5;
   int nBits = n & 0x1F;
   this.intLen -= nInts;
   if (nBits == 0) return;
   int bitsInHighWord = BigInteger.bitLen(value[offset]);
   if (nBits >= bitsInHighWord) {
     this.primitiveLeftShift(32 - nBits);
     this.intLen--;
   } else {
     primitiveRightShift(nBits);
   }
 }
Ejemplo n.º 3
0
  /** Left shift this MutableBigInteger n bits. */
  void leftShift(int n) {
    /*
     * If there is enough storage space in this MutableBigInteger already
     * the available space will be used. Space to the right of the used
     * ints in the value array is faster to utilize, so the extra space
     * will be taken from the right if possible.
     */
    if (intLen == 0) return;
    int nInts = n >>> 5;
    int nBits = n & 0x1F;
    int bitsInHighWord = BigInteger.bitLen(value[offset]);

    // If shift can be done without moving words, do so
    if (n <= (32 - bitsInHighWord)) {
      primitiveLeftShift(nBits);
      return;
    }

    int newLen = intLen + nInts + 1;
    if (nBits <= (32 - bitsInHighWord)) newLen--;
    if (value.length < newLen) {
      // The array must grow
      int[] result = new int[newLen];
      for (int i = 0; i < intLen; i++) result[i] = value[offset + i];
      setValue(result, newLen);
    } else if (value.length - offset >= newLen) {
      // Use space on right
      for (int i = 0; i < newLen - intLen; i++) value[offset + intLen + i] = 0;
    } else {
      // Must use space on left
      for (int i = 0; i < intLen; i++) value[i] = value[offset + i];
      for (int i = intLen; i < newLen; i++) value[i] = 0;
      offset = 0;
    }
    intLen = newLen;
    if (nBits == 0) return;
    if (nBits <= (32 - bitsInHighWord)) primitiveLeftShift(nBits);
    else primitiveRightShift(32 - nBits);
  }
Ejemplo n.º 4
0
  /**
   * Calculates the quotient and remainder of this div b and places them in the MutableBigInteger
   * objects provided.
   *
   * <p>Uses Algorithm D in Knuth section 4.3.1. Many optimizations to that algorithm have been
   * adapted from the Colin Plumb C library. It special cases one word divisors for speed. The
   * contents of a and b are not changed.
   */
  void divide(MutableBigInteger b, MutableBigInteger quotient, MutableBigInteger rem) {
    if (b.intLen == 0) throw new ArithmeticException("BigInteger divide by zero");

    // Dividend is zero
    if (intLen == 0) {
      quotient.intLen = quotient.offset = rem.intLen = rem.offset = 0;
      return;
    }

    int cmp = compare(b);

    // Dividend less than divisor
    if (cmp < 0) {
      quotient.intLen = quotient.offset = 0;
      rem.copyValue(this);
      return;
    }
    // Dividend equal to divisor
    if (cmp == 0) {
      quotient.value[0] = quotient.intLen = 1;
      quotient.offset = rem.intLen = rem.offset = 0;
      return;
    }

    quotient.clear();

    // Special case one word divisor
    if (b.intLen == 1) {
      rem.copyValue(this);
      rem.divideOneWord(b.value[b.offset], quotient);
      return;
    }

    // Copy divisor value to protect divisor
    int[] d = new int[b.intLen];
    for (int i = 0; i < b.intLen; i++) d[i] = b.value[b.offset + i];
    int dlen = b.intLen;

    // Remainder starts as dividend with space for a leading zero
    if (rem.value.length < intLen + 1) rem.value = new int[intLen + 1];

    for (int i = 0; i < intLen; i++) rem.value[i + 1] = value[i + offset];
    rem.intLen = intLen;
    rem.offset = 1;

    int nlen = rem.intLen;

    // Set the quotient size
    int limit = nlen - dlen + 1;
    if (quotient.value.length < limit) {
      quotient.value = new int[limit];
      quotient.offset = 0;
    }
    quotient.intLen = limit;
    int[] q = quotient.value;

    // D1 normalize the divisor
    int shift = 32 - BigInteger.bitLen(d[0]);
    if (shift > 0) {
      // First shift will not grow array
      BigInteger.primitiveLeftShift(d, dlen, shift);
      // But this one might
      rem.leftShift(shift);
    }

    // Must insert leading 0 in rem if its length did not change
    if (rem.intLen == nlen) {
      rem.offset = 0;
      rem.value[0] = 0;
      rem.intLen++;
    }

    int dh = d[0];
    long dhLong = dh & LONG_MASK;
    int dl = d[1];
    int[] qWord = new int[2];

    // D2 Initialize j
    for (int j = 0; j < limit; j++) {
      // D3 Calculate qhat
      // estimate qhat
      int qhat = 0;
      int qrem = 0;
      boolean skipCorrection = false;
      int nh = rem.value[j + rem.offset];
      int nh2 = nh + 0x80000000;
      int nm = rem.value[j + 1 + rem.offset];

      if (nh == dh) {
        qhat = ~0;
        qrem = nh + nm;
        skipCorrection = qrem + 0x80000000 < nh2;
      } else {
        long nChunk = (((long) nh) << 32) | (nm & LONG_MASK);
        if (nChunk >= 0) {
          qhat = (int) (nChunk / dhLong);
          qrem = (int) (nChunk - (qhat * dhLong));
        } else {
          divWord(qWord, nChunk, dh);
          qhat = qWord[0];
          qrem = qWord[1];
        }
      }

      if (qhat == 0) continue;

      if (!skipCorrection) { // Correct qhat
        long nl = rem.value[j + 2 + rem.offset] & LONG_MASK;
        long rs = ((qrem & LONG_MASK) << 32) | nl;
        long estProduct = (dl & LONG_MASK) * (qhat & LONG_MASK);

        if (unsignedLongCompare(estProduct, rs)) {
          qhat--;
          qrem = (int) ((qrem & LONG_MASK) + dhLong);
          if ((qrem & LONG_MASK) >= dhLong) {
            estProduct = (dl & LONG_MASK) * (qhat & LONG_MASK);
            rs = ((qrem & LONG_MASK) << 32) | nl;
            if (unsignedLongCompare(estProduct, rs)) qhat--;
          }
        }
      }

      // D4 Multiply and subtract
      rem.value[j + rem.offset] = 0;
      int borrow = mulsub(rem.value, d, qhat, dlen, j + rem.offset);

      // D5 Test remainder
      if (borrow + 0x80000000 > nh2) {
        // D6 Add back
        divadd(d, rem.value, j + 1 + rem.offset);
        qhat--;
      }

      // Store the quotient digit
      q[j] = qhat;
    } // D7 loop on j

    // D8 Unnormalize
    if (shift > 0) rem.rightShift(shift);

    rem.normalize();
    quotient.normalize();
  }