/** * 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(); }
/** 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); } }
/** 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); }
/** * 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(); }