src/share/classes/java/math/BigInteger.java
Print this page
rev 7721 : 8014319: Faster division of large integers
Summary: Implement Burnickel-Ziegler division algorithm in BigInteger
Reviewed-by: bpb, martin
Contributed-by: Tim Buktu <tbuktu@hotmail.com>
@@ -31,11 +31,10 @@
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamField;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.Random;
import sun.misc.DoubleConsts;
import sun.misc.FloatConsts;
@@ -99,10 +98,11 @@
*
* @see BigDecimal
* @author Josh Bloch
* @author Michael McCloskey
* @author Alan Eliasen
+ * @author Timothy Buktu
* @since JDK1.1
*/
public class BigInteger extends Number implements Comparable<BigInteger> {
/**
@@ -213,10 +213,18 @@
* experimentally to work well.
*/
private static final int TOOM_COOK_SQUARE_THRESHOLD = 140;
/**
+ * The threshold value for using Burnikel-Ziegler division. If the number
+ * of ints in the number are larger than this value,
+ * Burnikel-Ziegler division will be used. This value is found
+ * experimentally to work well.
+ */
+ static final int BURNIKEL_ZIEGLER_THRESHOLD = 50;
+
+ /**
* The threshold value for using Schoenhage recursive base conversion. If
* the number of ints in the number are larger than this value,
* the Schoenhage algorithm will be used. In practice, it appears that the
* Schoenhage routine is faster for any threshold down to 2, and is
* relatively flat for thresholds between 2-25, so this choice may be
@@ -1934,15 +1942,30 @@
* @param val value by which this BigInteger is to be divided.
* @return {@code this / val}
* @throws ArithmeticException if {@code val} is zero.
*/
public BigInteger divide(BigInteger val) {
+ if (mag.length<BURNIKEL_ZIEGLER_THRESHOLD || val.mag.length<BURNIKEL_ZIEGLER_THRESHOLD)
+ return divideKnuth(val);
+ else
+ return divideBurnikelZiegler(val);
+ }
+
+ /**
+ * Returns a BigInteger whose value is {@code (this / val)} using an O(n^2) algorithm from Knuth.
+ *
+ * @param val value by which this BigInteger is to be divided.
+ * @return {@code this / val}
+ * @throws ArithmeticException if {@code val} is zero.
+ * @see MutableBigInteger#divideKnuth(MutableBigInteger, MutableBigInteger, boolean)
+ */
+ private BigInteger divideKnuth(BigInteger val) {
MutableBigInteger q = new MutableBigInteger(),
a = new MutableBigInteger(this.mag),
b = new MutableBigInteger(val.mag);
- a.divide(b, q, false);
+ a.divideKnuth(b, q, false);
return q.toBigInteger(this.signum * val.signum);
}
/**
* Returns an array of two BigIntegers containing {@code (this / val)}
@@ -1954,15 +1977,23 @@
* is the initial element, and the remainder {@code (this % val)}
* is the final element.
* @throws ArithmeticException if {@code val} is zero.
*/
public BigInteger[] divideAndRemainder(BigInteger val) {
+ if (mag.length<BURNIKEL_ZIEGLER_THRESHOLD || val.mag.length<BURNIKEL_ZIEGLER_THRESHOLD)
+ return divideAndRemainderKnuth(val);
+ else
+ return divideAndRemainderBurnikelZiegler(val);
+ }
+
+ /** Long division */
+ private BigInteger[] divideAndRemainderKnuth(BigInteger val) {
BigInteger[] result = new BigInteger[2];
MutableBigInteger q = new MutableBigInteger(),
a = new MutableBigInteger(this.mag),
b = new MutableBigInteger(val.mag);
- MutableBigInteger r = a.divide(b, q);
+ MutableBigInteger r = a.divideKnuth(b, q);
result[0] = q.toBigInteger(this.signum == val.signum ? 1 : -1);
result[1] = r.toBigInteger(this.signum);
return result;
}
@@ -1973,15 +2004,55 @@
* remainder computed.
* @return {@code this % val}
* @throws ArithmeticException if {@code val} is zero.
*/
public BigInteger remainder(BigInteger val) {
+ if (mag.length<BURNIKEL_ZIEGLER_THRESHOLD || val.mag.length<BURNIKEL_ZIEGLER_THRESHOLD)
+ return remainderKnuth(val);
+ else
+ return remainderBurnikelZiegler(val);
+ }
+
+ /** Long division */
+ private BigInteger remainderKnuth(BigInteger val) {
MutableBigInteger q = new MutableBigInteger(),
a = new MutableBigInteger(this.mag),
b = new MutableBigInteger(val.mag);
- return a.divide(b, q).toBigInteger(this.signum);
+ return a.divideKnuth(b, q).toBigInteger(this.signum);
+ }
+
+ /**
+ * Calculates {@code this / val} using the Burnikel-Ziegler algorithm.
+ * @param val the divisor
+ * @return {@code this / val}
+ */
+ private BigInteger divideBurnikelZiegler(BigInteger val) {
+ return divideAndRemainderBurnikelZiegler(val)[0];
+ }
+
+ /**
+ * Calculates {@code this % val} using the Burnikel-Ziegler algorithm.
+ * @param val the divisor
+ * @return {@code this % val}
+ */
+ private BigInteger remainderBurnikelZiegler(BigInteger val) {
+ return divideAndRemainderBurnikelZiegler(val)[1];
+ }
+
+ /**
+ * Computes {@code this / val} and {@code this % val} using the
+ * Burnikel-Ziegler algorithm.
+ * @param val the divisor
+ * @return an array containing the quotient and remainder
+ */
+ private BigInteger[] divideAndRemainderBurnikelZiegler(BigInteger val) {
+ MutableBigInteger q = new MutableBigInteger();
+ MutableBigInteger r = new MutableBigInteger(this).divideAndRemainderBurnikelZiegler(new MutableBigInteger(val), q);
+ BigInteger qBigInt = q.isZero() ? ZERO : q.toBigInteger(signum*val.signum);
+ BigInteger rBigInt = r.isZero() ? ZERO : r.toBigInteger(signum);
+ return new BigInteger[] {qBigInt, rBigInt};
}
/**
* Returns a BigInteger whose value is <tt>(this<sup>exponent</sup>)</tt>.
* Note that {@code exponent} is an integer rather than a BigInteger.
@@ -3397,11 +3468,11 @@
return buf.toString();
}
/**
* Converts the specified BigInteger to a string and appends to
- * <code>sb</code>. This implements the recursive Schoenhage algorithm
+ * {@code sb}. This implements the recursive Schoenhage algorithm
* for base conversions.
* <p/>
* See Knuth, Donald, _The Art of Computer Programming_, Vol. 2,
* Answers to Exercises (4.4) Question 14.
*
@@ -3448,11 +3519,11 @@
/**
* Returns the value radix^(2^exponent) from the cache.
* If this value doesn't already exist in the cache, it is added.
* <p/>
* This could be changed to a more complicated caching method using
- * <code>Future</code>.
+ * {@code Future}.
*/
private static BigInteger getRadixConversionCache(int radix, int exponent) {
BigInteger[] cacheLine = powerCache[radix]; // volatile read
if (exponent < cacheLine.length) {
return cacheLine[exponent];