提交 36fe3287 编写于 作者: B bpb

8014319: Faster division of large integers

Summary: Implement Burnickel-Ziegler division algorithm in BigInteger
Reviewed-by: bpb, martin
Contributed-by: NTim Buktu <tbuktu@hotmail.com>
上级 e48f93eb
...@@ -33,7 +33,6 @@ import java.io.IOException; ...@@ -33,7 +33,6 @@ import java.io.IOException;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
import java.io.ObjectOutputStream; import java.io.ObjectOutputStream;
import java.io.ObjectStreamField; import java.io.ObjectStreamField;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Random; import java.util.Random;
import sun.misc.DoubleConsts; import sun.misc.DoubleConsts;
...@@ -101,6 +100,7 @@ import sun.misc.FloatConsts; ...@@ -101,6 +100,7 @@ import sun.misc.FloatConsts;
* @author Josh Bloch * @author Josh Bloch
* @author Michael McCloskey * @author Michael McCloskey
* @author Alan Eliasen * @author Alan Eliasen
* @author Timothy Buktu
* @since JDK1.1 * @since JDK1.1
*/ */
...@@ -214,6 +214,14 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -214,6 +214,14 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
*/ */
private static final int TOOM_COOK_SQUARE_THRESHOLD = 140; 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 threshold value for using Schoenhage recursive base conversion. If
* the number of ints in the number are larger than this value, * the number of ints in the number are larger than this value,
...@@ -1936,11 +1944,26 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -1936,11 +1944,26 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
* @throws ArithmeticException if {@code val} is zero. * @throws ArithmeticException if {@code val} is zero.
*/ */
public BigInteger divide(BigInteger val) { 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(), MutableBigInteger q = new MutableBigInteger(),
a = new MutableBigInteger(this.mag), a = new MutableBigInteger(this.mag),
b = new MutableBigInteger(val.mag); b = new MutableBigInteger(val.mag);
a.divide(b, q, false); a.divideKnuth(b, q, false);
return q.toBigInteger(this.signum * val.signum); return q.toBigInteger(this.signum * val.signum);
} }
...@@ -1956,11 +1979,19 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -1956,11 +1979,19 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
* @throws ArithmeticException if {@code val} is zero. * @throws ArithmeticException if {@code val} is zero.
*/ */
public BigInteger[] divideAndRemainder(BigInteger val) { 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]; BigInteger[] result = new BigInteger[2];
MutableBigInteger q = new MutableBigInteger(), MutableBigInteger q = new MutableBigInteger(),
a = new MutableBigInteger(this.mag), a = new MutableBigInteger(this.mag),
b = new MutableBigInteger(val.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[0] = q.toBigInteger(this.signum == val.signum ? 1 : -1);
result[1] = r.toBigInteger(this.signum); result[1] = r.toBigInteger(this.signum);
return result; return result;
...@@ -1975,11 +2006,51 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -1975,11 +2006,51 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
* @throws ArithmeticException if {@code val} is zero. * @throws ArithmeticException if {@code val} is zero.
*/ */
public BigInteger remainder(BigInteger val) { 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(), MutableBigInteger q = new MutableBigInteger(),
a = new MutableBigInteger(this.mag), a = new MutableBigInteger(this.mag),
b = new MutableBigInteger(val.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};
} }
/** /**
...@@ -3399,7 +3470,7 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -3399,7 +3470,7 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
/** /**
* Converts the specified BigInteger to a string and appends to * 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. * for base conversions.
* <p/> * <p/>
* See Knuth, Donald, _The Art of Computer Programming_, Vol. 2, * See Knuth, Donald, _The Art of Computer Programming_, Vol. 2,
...@@ -3450,7 +3521,7 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -3450,7 +3521,7 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
* If this value doesn't already exist in the cache, it is added. * If this value doesn't already exist in the cache, it is added.
* <p/> * <p/>
* This could be changed to a more complicated caching method using * This could be changed to a more complicated caching method using
* <code>Future</code>. * {@code Future}.
*/ */
private static BigInteger getRadixConversionCache(int radix, int exponent) { private static BigInteger getRadixConversionCache(int radix, int exponent) {
BigInteger[] cacheLine = powerCache[radix]; // volatile read BigInteger[] cacheLine = powerCache[radix]; // volatile read
......
...@@ -43,12 +43,12 @@ import java.util.Random; ...@@ -43,12 +43,12 @@ import java.util.Random;
* this test is a strong assurance that the BigInteger operations * this test is a strong assurance that the BigInteger operations
* are working correctly. * are working correctly.
* *
* Three arguments may be specified which give the number of * Four arguments may be specified which give the number of
* decimal digits you desire in the three batches of test numbers. * decimal digits you desire in the four batches of test numbers.
* *
* The tests are performed on arrays of random numbers which are * The tests are performed on arrays of random numbers which are
* generated by a Random class as well as special cases which * generated by a Random class as well as special cases which
* throw in boundary numbers such as 0, 1, maximum sized, etc. * throw in boundary numbers such as 0, 1, maximum SIZEd, etc.
* *
*/ */
public class BigIntegerTest { public class BigIntegerTest {
...@@ -63,11 +63,14 @@ public class BigIntegerTest { ...@@ -63,11 +63,14 @@ public class BigIntegerTest {
// //
// SCHOENHAGE_BASE_CONVERSION_THRESHOLD = 8 ints = 256 bits // SCHOENHAGE_BASE_CONVERSION_THRESHOLD = 8 ints = 256 bits
// //
// BURNIKEL_ZIEGLER_THRESHOLD = 50 ints = 1600 bits
//
static final int BITS_KARATSUBA = 1600; static final int BITS_KARATSUBA = 1600;
static final int BITS_TOOM_COOK = 2400; static final int BITS_TOOM_COOK = 2400;
static final int BITS_KARATSUBA_SQUARE = 2880; static final int BITS_KARATSUBA_SQUARE = 2880;
static final int BITS_TOOM_COOK_SQUARE = 4480; static final int BITS_TOOM_COOK_SQUARE = 4480;
static final int BITS_SCHOENHAGE_BASE = 256; static final int BITS_SCHOENHAGE_BASE = 256;
static final int BITS_BURNIKEL_ZIEGLER = 1600;
static final int ORDER_SMALL = 60; static final int ORDER_SMALL = 60;
static final int ORDER_MEDIUM = 100; static final int ORDER_MEDIUM = 100;
...@@ -80,14 +83,15 @@ public class BigIntegerTest { ...@@ -80,14 +83,15 @@ public class BigIntegerTest {
// #bits for testing Toom-Cook squaring // #bits for testing Toom-Cook squaring
static final int ORDER_TOOM_COOK_SQUARE = 4600; static final int ORDER_TOOM_COOK_SQUARE = 4600;
static final int SIZE = 1000; // numbers per batch
static Random rnd = new Random(); static Random rnd = new Random();
static int size = 1000; // numbers per batch
static boolean failure = false; static boolean failure = false;
public static void pow(int order) { public static void pow(int order) {
int failCount1 = 0; int failCount1 = 0;
for (int i=0; i<size; i++) { for (int i=0; i<SIZE; i++) {
// Test identity x^power == x*x*x ... *x // Test identity x^power == x*x*x ... *x
int power = rnd.nextInt(6) + 2; int power = rnd.nextInt(6) + 2;
BigInteger x = fetchNumber(order); BigInteger x = fetchNumber(order);
...@@ -106,7 +110,7 @@ public class BigIntegerTest { ...@@ -106,7 +110,7 @@ public class BigIntegerTest {
public static void square(int order) { public static void square(int order) {
int failCount1 = 0; int failCount1 = 0;
for (int i=0; i<size; i++) { for (int i=0; i<SIZE; i++) {
// Test identity x^2 == x*x // Test identity x^2 == x*x
BigInteger x = fetchNumber(order); BigInteger x = fetchNumber(order);
BigInteger xx = x.multiply(x); BigInteger xx = x.multiply(x);
...@@ -121,7 +125,7 @@ public class BigIntegerTest { ...@@ -121,7 +125,7 @@ public class BigIntegerTest {
public static void arithmetic(int order) { public static void arithmetic(int order) {
int failCount = 0; int failCount = 0;
for (int i=0; i<size; i++) { for (int i=0; i<SIZE; i++) {
BigInteger x = fetchNumber(order); BigInteger x = fetchNumber(order);
while(x.compareTo(BigInteger.ZERO) != 1) while(x.compareTo(BigInteger.ZERO) != 1)
x = fetchNumber(order); x = fetchNumber(order);
...@@ -187,7 +191,7 @@ public class BigIntegerTest { ...@@ -187,7 +191,7 @@ public class BigIntegerTest {
int failCount = 0; int failCount = 0;
BigInteger base = BigInteger.ONE.shiftLeft(BITS_KARATSUBA - 32 - 1); BigInteger base = BigInteger.ONE.shiftLeft(BITS_KARATSUBA - 32 - 1);
for (int i=0; i<size; i++) { for (int i=0; i<SIZE; i++) {
BigInteger x = fetchNumber(BITS_KARATSUBA - 32 - 1); BigInteger x = fetchNumber(BITS_KARATSUBA - 32 - 1);
BigInteger u = base.add(x); BigInteger u = base.add(x);
int a = 1 + rnd.nextInt(31); int a = 1 + rnd.nextInt(31);
...@@ -210,7 +214,7 @@ public class BigIntegerTest { ...@@ -210,7 +214,7 @@ public class BigIntegerTest {
failCount = 0; failCount = 0;
base = base.shiftLeft(BITS_TOOM_COOK - BITS_KARATSUBA); base = base.shiftLeft(BITS_TOOM_COOK - BITS_KARATSUBA);
for (int i=0; i<size; i++) { for (int i=0; i<SIZE; i++) {
BigInteger x = fetchNumber(BITS_TOOM_COOK - 32 - 1); BigInteger x = fetchNumber(BITS_TOOM_COOK - 32 - 1);
BigInteger u = base.add(x); BigInteger u = base.add(x);
BigInteger u2 = u.shiftLeft(1); BigInteger u2 = u.shiftLeft(1);
...@@ -241,7 +245,7 @@ public class BigIntegerTest { ...@@ -241,7 +245,7 @@ public class BigIntegerTest {
int failCount = 0; int failCount = 0;
BigInteger base = BigInteger.ONE.shiftLeft(BITS_KARATSUBA_SQUARE - 32 - 1); BigInteger base = BigInteger.ONE.shiftLeft(BITS_KARATSUBA_SQUARE - 32 - 1);
for (int i=0; i<size; i++) { for (int i=0; i<SIZE; i++) {
BigInteger x = fetchNumber(BITS_KARATSUBA_SQUARE - 32 - 1); BigInteger x = fetchNumber(BITS_KARATSUBA_SQUARE - 32 - 1);
BigInteger u = base.add(x); BigInteger u = base.add(x);
int a = 1 + rnd.nextInt(31); int a = 1 + rnd.nextInt(31);
...@@ -259,7 +263,7 @@ public class BigIntegerTest { ...@@ -259,7 +263,7 @@ public class BigIntegerTest {
failCount = 0; failCount = 0;
base = base.shiftLeft(BITS_TOOM_COOK_SQUARE - BITS_KARATSUBA_SQUARE); base = base.shiftLeft(BITS_TOOM_COOK_SQUARE - BITS_KARATSUBA_SQUARE);
for (int i=0; i<size; i++) { for (int i=0; i<SIZE; i++) {
BigInteger x = fetchNumber(BITS_TOOM_COOK_SQUARE - 32 - 1); BigInteger x = fetchNumber(BITS_TOOM_COOK_SQUARE - 32 - 1);
BigInteger u = base.add(x); BigInteger u = base.add(x);
int a = 1 + rnd.nextInt(31); int a = 1 + rnd.nextInt(31);
...@@ -276,10 +280,61 @@ public class BigIntegerTest { ...@@ -276,10 +280,61 @@ public class BigIntegerTest {
report("squareLarge Toom-Cook", failCount); report("squareLarge Toom-Cook", failCount);
} }
/**
* Sanity test for Burnikel-Ziegler division. The Burnikel-Ziegler division
* algorithm is used when each of the dividend and the divisor has at least
* a specified number of ints in its representation. This test is based on
* the observation that if {@code w = u*pow(2,a)} and {@code z = v*pow(2,b)}
* where {@code abs(u) > abs(v)} and {@code a > b && b > 0}, then if
* {@code w/z = q1*z + r1} and {@code u/v = q2*v + r2}, then
* {@code q1 = q2*pow(2,a-b)} and {@code r1 = r2*pow(2,b)}. The test
* ensures that {@code v} is just under the B-Z threshold and that {@code w}
* and {@code z} are both over the threshold. This implies that {@code u/v}
* uses the standard division algorithm and {@code w/z} uses the B-Z
* algorithm. The results of the two algorithms are then compared using the
* observation described in the foregoing and if they are not equal a
* failure is logged.
*/
public static void divideLarge() {
int failCount = 0;
BigInteger base = BigInteger.ONE.shiftLeft(BITS_BURNIKEL_ZIEGLER - 33);
for (int i=0; i<SIZE; i++) {
BigInteger addend = new BigInteger(BITS_BURNIKEL_ZIEGLER - 34, rnd);
BigInteger v = base.add(addend);
BigInteger u = v.multiply(BigInteger.valueOf(2 + rnd.nextInt(Short.MAX_VALUE - 1)));
if(rnd.nextBoolean()) {
u = u.negate();
}
if(rnd.nextBoolean()) {
v = v.negate();
}
int a = 17 + rnd.nextInt(16);
int b = 1 + rnd.nextInt(16);
BigInteger w = u.multiply(BigInteger.valueOf(1L << a));
BigInteger z = v.multiply(BigInteger.valueOf(1L << b));
BigInteger[] divideResult = u.divideAndRemainder(v);
divideResult[0] = divideResult[0].multiply(BigInteger.valueOf(1L << (a - b)));
divideResult[1] = divideResult[1].multiply(BigInteger.valueOf(1L << b));
BigInteger[] bzResult = w.divideAndRemainder(z);
if (divideResult[0].compareTo(bzResult[0]) != 0 ||
divideResult[1].compareTo(bzResult[1]) != 0) {
failCount++;
}
}
report("divideLarge", failCount);
}
public static void bitCount() { public static void bitCount() {
int failCount = 0; int failCount = 0;
for (int i=0; i<size*10; i++) { for (int i=0; i<SIZE*10; i++) {
int x = rnd.nextInt(); int x = rnd.nextInt();
BigInteger bigX = BigInteger.valueOf((long)x); BigInteger bigX = BigInteger.valueOf((long)x);
int bit = (x < 0 ? 0 : 1); int bit = (x < 0 ? 0 : 1);
...@@ -300,7 +355,7 @@ public class BigIntegerTest { ...@@ -300,7 +355,7 @@ public class BigIntegerTest {
public static void bitLength() { public static void bitLength() {
int failCount = 0; int failCount = 0;
for (int i=0; i<size*10; i++) { for (int i=0; i<SIZE*10; i++) {
int x = rnd.nextInt(); int x = rnd.nextInt();
BigInteger bigX = BigInteger.valueOf((long)x); BigInteger bigX = BigInteger.valueOf((long)x);
int signBit = (x < 0 ? 0x80000000 : 0); int signBit = (x < 0 ? 0x80000000 : 0);
...@@ -321,7 +376,7 @@ public class BigIntegerTest { ...@@ -321,7 +376,7 @@ public class BigIntegerTest {
public static void bitOps(int order) { public static void bitOps(int order) {
int failCount1 = 0, failCount2 = 0, failCount3 = 0; int failCount1 = 0, failCount2 = 0, failCount3 = 0;
for (int i=0; i<size*5; i++) { for (int i=0; i<SIZE*5; i++) {
BigInteger x = fetchNumber(order); BigInteger x = fetchNumber(order);
BigInteger y; BigInteger y;
...@@ -351,7 +406,7 @@ public class BigIntegerTest { ...@@ -351,7 +406,7 @@ public class BigIntegerTest {
report("clearBit/testBit for " + order + " bits", failCount1); report("clearBit/testBit for " + order + " bits", failCount1);
report("flipBit/testBit for " + order + " bits", failCount2); report("flipBit/testBit for " + order + " bits", failCount2);
for (int i=0; i<size*5; i++) { for (int i=0; i<SIZE*5; i++) {
BigInteger x = fetchNumber(order); BigInteger x = fetchNumber(order);
// Test getLowestSetBit() // Test getLowestSetBit()
...@@ -375,7 +430,7 @@ public class BigIntegerTest { ...@@ -375,7 +430,7 @@ public class BigIntegerTest {
// Test identity x^y == x|y &~ x&y // Test identity x^y == x|y &~ x&y
int failCount = 0; int failCount = 0;
for (int i=0; i<size; i++) { for (int i=0; i<SIZE; i++) {
BigInteger x = fetchNumber(order); BigInteger x = fetchNumber(order);
BigInteger y = fetchNumber(order); BigInteger y = fetchNumber(order);
BigInteger z = x.xor(y); BigInteger z = x.xor(y);
...@@ -387,7 +442,7 @@ public class BigIntegerTest { ...@@ -387,7 +442,7 @@ public class BigIntegerTest {
// Test identity x &~ y == ~(~x | y) // Test identity x &~ y == ~(~x | y)
failCount = 0; failCount = 0;
for (int i=0; i<size; i++) { for (int i=0; i<SIZE; i++) {
BigInteger x = fetchNumber(order); BigInteger x = fetchNumber(order);
BigInteger y = fetchNumber(order); BigInteger y = fetchNumber(order);
BigInteger z = x.andNot(y); BigInteger z = x.andNot(y);
...@@ -440,7 +495,7 @@ public class BigIntegerTest { ...@@ -440,7 +495,7 @@ public class BigIntegerTest {
public static void divideAndRemainder(int order) { public static void divideAndRemainder(int order) {
int failCount1 = 0; int failCount1 = 0;
for (int i=0; i<size; i++) { for (int i=0; i<SIZE; i++) {
BigInteger x = fetchNumber(order).abs(); BigInteger x = fetchNumber(order).abs();
while(x.compareTo(BigInteger.valueOf(3L)) != 1) while(x.compareTo(BigInteger.valueOf(3L)) != 1)
x = fetchNumber(order).abs(); x = fetchNumber(order).abs();
...@@ -519,7 +574,7 @@ public class BigIntegerTest { ...@@ -519,7 +574,7 @@ public class BigIntegerTest {
public static void byteArrayConv(int order) { public static void byteArrayConv(int order) {
int failCount = 0; int failCount = 0;
for (int i=0; i<size; i++) { for (int i=0; i<SIZE; i++) {
BigInteger x = fetchNumber(order); BigInteger x = fetchNumber(order);
while (x.equals(BigInteger.ZERO)) while (x.equals(BigInteger.ZERO))
x = fetchNumber(order); x = fetchNumber(order);
...@@ -536,7 +591,7 @@ public class BigIntegerTest { ...@@ -536,7 +591,7 @@ public class BigIntegerTest {
public static void modInv(int order) { public static void modInv(int order) {
int failCount = 0, successCount = 0, nonInvCount = 0; int failCount = 0, successCount = 0, nonInvCount = 0;
for (int i=0; i<size; i++) { for (int i=0; i<SIZE; i++) {
BigInteger x = fetchNumber(order); BigInteger x = fetchNumber(order);
while(x.equals(BigInteger.ZERO)) while(x.equals(BigInteger.ZERO))
x = fetchNumber(order); x = fetchNumber(order);
...@@ -565,7 +620,7 @@ public class BigIntegerTest { ...@@ -565,7 +620,7 @@ public class BigIntegerTest {
public static void modExp(int order1, int order2) { public static void modExp(int order1, int order2) {
int failCount = 0; int failCount = 0;
for (int i=0; i<size/10; i++) { for (int i=0; i<SIZE/10; i++) {
BigInteger m = fetchNumber(order1).abs(); BigInteger m = fetchNumber(order1).abs();
while(m.compareTo(BigInteger.ONE) != 1) while(m.compareTo(BigInteger.ONE) != 1)
m = fetchNumber(order1).abs(); m = fetchNumber(order1).abs();
...@@ -883,8 +938,8 @@ public class BigIntegerTest { ...@@ -883,8 +938,8 @@ public class BigIntegerTest {
/** /**
* Main to interpret arguments and run several tests. * Main to interpret arguments and run several tests.
* *
* Up to three arguments may be given to specify the size of BigIntegers * Up to three arguments may be given to specify the SIZE of BigIntegers
* used for call parameters 1, 2, and 3. The size is interpreted as * used for call parameters 1, 2, and 3. The SIZE is interpreted as
* the maximum number of decimal digits that the parameters will have. * the maximum number of decimal digits that the parameters will have.
* *
*/ */
...@@ -945,6 +1000,7 @@ public class BigIntegerTest { ...@@ -945,6 +1000,7 @@ public class BigIntegerTest {
multiplyLarge(); multiplyLarge();
squareLarge(); squareLarge();
divideLarge();
if (failure) if (failure)
throw new RuntimeException("Failure in BigIntegerTest."); throw new RuntimeException("Failure in BigIntegerTest.");
...@@ -952,7 +1008,7 @@ public class BigIntegerTest { ...@@ -952,7 +1008,7 @@ public class BigIntegerTest {
/* /*
* Get a random or boundary-case number. This is designed to provide * Get a random or boundary-case number. This is designed to provide
* a lot of numbers that will find failure points, such as max sized * a lot of numbers that will find failure points, such as max SIZEd
* numbers, empty BigIntegers, etc. * numbers, empty BigIntegers, etc.
* *
* If order is less than 2, order is changed to 2. * If order is less than 2, order is changed to 2.
...@@ -987,13 +1043,13 @@ public class BigIntegerTest { ...@@ -987,13 +1043,13 @@ public class BigIntegerTest {
break; break;
case 4: // Random bit density case 4: // Random bit density
int iterations = rnd.nextInt(order-1); byte[] val = new byte[(order+7)/8];
result = BigInteger.ONE.shiftLeft(rnd.nextInt(order)); int iterations = rnd.nextInt(order);
for(int i=0; i<iterations; i++) { for (int i=0; i<iterations; i++) {
BigInteger temp = BigInteger.ONE.shiftLeft( int bitIdx = rnd.nextInt(order);
rnd.nextInt(order)); val[bitIdx/8] |= 1 << (bitIdx%8);
result = result.or(temp);
} }
result = new BigInteger(1, val);
break; break;
case 5: // Runs of consecutive ones and zeros case 5: // Runs of consecutive ones and zeros
result = ZERO; result = ZERO;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册