4837946: Faster multiplication and exponentiation of large integers
4646474: BigInteger.pow() algorithm slow in 1.4.0 Implement Karatsuba and 3-way Toom-Cook multiplication as well as exponentiation using Karatsuba and Toom-Cook squaring. Reviewed-by: alanb, bpb, martin
This commit is contained in:
parent
adc454c0fe
commit
3a76795991
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -3538,24 +3538,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
|
||||
return expandBigIntegerTenPowers(n);
|
||||
}
|
||||
|
||||
if (n < 1024*524288) {
|
||||
// BigInteger.pow is slow, so make 10**n by constructing a
|
||||
// BigInteger from a character string (still not very fast)
|
||||
// which occupies no more than 1GB (!) of memory.
|
||||
char tenpow[] = new char[n + 1];
|
||||
tenpow[0] = '1';
|
||||
for (int i = 1; i <= n; i++) {
|
||||
tenpow[i] = '0';
|
||||
}
|
||||
return new BigInteger(tenpow, 1, tenpow.length);
|
||||
}
|
||||
|
||||
if ((n & 0x1) == 0x1) {
|
||||
return BigInteger.TEN.multiply(bigTenToThe(n - 1));
|
||||
} else {
|
||||
BigInteger tmp = bigTenToThe(n/2);
|
||||
return tmp.multiply(tmp);
|
||||
}
|
||||
return BigInteger.TEN.pow(n);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -29,9 +29,12 @@
|
||||
|
||||
package java.math;
|
||||
|
||||
import java.util.Random;
|
||||
import java.io.*;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.ObjectStreamField;
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Immutable arbitrary-precision integers. All operations behave as if
|
||||
@ -94,6 +97,7 @@ import java.util.Arrays;
|
||||
* @see BigDecimal
|
||||
* @author Josh Bloch
|
||||
* @author Michael McCloskey
|
||||
* @author Alan Eliasen
|
||||
* @since JDK1.1
|
||||
*/
|
||||
|
||||
@ -174,6 +178,39 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
|
||||
*/
|
||||
final static long LONG_MASK = 0xffffffffL;
|
||||
|
||||
/**
|
||||
* The threshold value for using Karatsuba multiplication. If the number
|
||||
* of ints in both mag arrays are greater than this number, then
|
||||
* Karatsuba multiplication will be used. This value is found
|
||||
* experimentally to work well.
|
||||
*/
|
||||
private static final int KARATSUBA_THRESHOLD = 50;
|
||||
|
||||
/**
|
||||
* The threshold value for using 3-way Toom-Cook multiplication.
|
||||
* If the number of ints in each mag array is greater than the
|
||||
* Karatsuba threshold, and the number of ints in at least one of
|
||||
* the mag arrays is greater than this threshold, then Toom-Cook
|
||||
* multiplication will be used.
|
||||
*/
|
||||
private static final int TOOM_COOK_THRESHOLD = 75;
|
||||
|
||||
/**
|
||||
* The threshold value for using Karatsuba squaring. If the number
|
||||
* of ints in the number are larger than this value,
|
||||
* Karatsuba squaring will be used. This value is found
|
||||
* experimentally to work well.
|
||||
*/
|
||||
private static final int KARATSUBA_SQUARE_THRESHOLD = 90;
|
||||
|
||||
/**
|
||||
* The threshold value for using Toom-Cook squaring. If the number
|
||||
* of ints in the number are larger than this value,
|
||||
* Toom-Cook squaring will be used. This value is found
|
||||
* experimentally to work well.
|
||||
*/
|
||||
private static final int TOOM_COOK_SQUARE_THRESHOLD = 140;
|
||||
|
||||
//Constructors
|
||||
|
||||
/**
|
||||
@ -522,15 +559,16 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
|
||||
|
||||
if (bitLength < 2)
|
||||
throw new ArithmeticException("bitLength < 2");
|
||||
// The cutoff of 95 was chosen empirically for best performance
|
||||
prime = (bitLength < 95 ? smallPrime(bitLength, certainty, rnd)
|
||||
prime = (bitLength < SMALL_PRIME_THRESHOLD
|
||||
? smallPrime(bitLength, certainty, rnd)
|
||||
: largePrime(bitLength, certainty, rnd));
|
||||
signum = 1;
|
||||
mag = prime.mag;
|
||||
}
|
||||
|
||||
// Minimum size in bits that the requested prime number has
|
||||
// before we use the large prime number generating algorithms
|
||||
// before we use the large prime number generating algorithms.
|
||||
// The cutoff of 95 was chosen empirically for best performance.
|
||||
private static final int SMALL_PRIME_THRESHOLD = 95;
|
||||
|
||||
// Certainty required to meet the spec of probablePrime
|
||||
@ -553,7 +591,6 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
|
||||
if (bitLength < 2)
|
||||
throw new ArithmeticException("bitLength < 2");
|
||||
|
||||
// The cutoff of 95 was chosen empirically for best performance
|
||||
return (bitLength < SMALL_PRIME_THRESHOLD ?
|
||||
smallPrime(bitLength, DEFAULT_PRIME_CERTAINTY, rnd) :
|
||||
largePrime(bitLength, DEFAULT_PRIME_CERTAINTY, rnd));
|
||||
@ -986,6 +1023,7 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
|
||||
private final static int MAX_CONSTANT = 16;
|
||||
private static BigInteger posConst[] = new BigInteger[MAX_CONSTANT+1];
|
||||
private static BigInteger negConst[] = new BigInteger[MAX_CONSTANT+1];
|
||||
|
||||
static {
|
||||
for (int i = 1; i <= MAX_CONSTANT; i++) {
|
||||
int[] magnitude = new int[1];
|
||||
@ -1014,6 +1052,11 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
|
||||
*/
|
||||
private static final BigInteger TWO = valueOf(2);
|
||||
|
||||
/**
|
||||
* The BigInteger constant -1. (Not exported.)
|
||||
*/
|
||||
private static final BigInteger NEGATIVE_ONE = valueOf(-1);
|
||||
|
||||
/**
|
||||
* The BigInteger constant ten.
|
||||
*
|
||||
@ -1290,17 +1333,29 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
|
||||
public BigInteger multiply(BigInteger val) {
|
||||
if (val.signum == 0 || signum == 0)
|
||||
return ZERO;
|
||||
int resultSign = signum == val.signum ? 1 : -1;
|
||||
if (val.mag.length == 1) {
|
||||
return multiplyByInt(mag,val.mag[0], resultSign);
|
||||
|
||||
int xlen = mag.length;
|
||||
int ylen = val.mag.length;
|
||||
|
||||
if ((xlen < KARATSUBA_THRESHOLD) || (ylen < KARATSUBA_THRESHOLD))
|
||||
{
|
||||
int resultSign = signum == val.signum ? 1 : -1;
|
||||
if (val.mag.length == 1) {
|
||||
return multiplyByInt(mag,val.mag[0], resultSign);
|
||||
}
|
||||
if(mag.length == 1) {
|
||||
return multiplyByInt(val.mag,mag[0], resultSign);
|
||||
}
|
||||
int[] result = multiplyToLen(mag, xlen,
|
||||
val.mag, ylen, null);
|
||||
result = trustedStripLeadingZeroInts(result);
|
||||
return new BigInteger(result, resultSign);
|
||||
}
|
||||
if(mag.length == 1) {
|
||||
return multiplyByInt(val.mag,mag[0], resultSign);
|
||||
}
|
||||
int[] result = multiplyToLen(mag, mag.length,
|
||||
val.mag, val.mag.length, null);
|
||||
result = trustedStripLeadingZeroInts(result);
|
||||
return new BigInteger(result, resultSign);
|
||||
else
|
||||
if ((xlen < TOOM_COOK_THRESHOLD) && (ylen < TOOM_COOK_THRESHOLD))
|
||||
return multiplyKaratsuba(this, val);
|
||||
else
|
||||
return multiplyToomCook3(this, val);
|
||||
}
|
||||
|
||||
private static BigInteger multiplyByInt(int[] x, int y, int sign) {
|
||||
@ -1401,6 +1456,272 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
|
||||
return z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies two BigIntegers using the Karatsuba multiplication
|
||||
* algorithm. This is a recursive divide-and-conquer algorithm which is
|
||||
* more efficient for large numbers than what is commonly called the
|
||||
* "grade-school" algorithm used in multiplyToLen. If the numbers to be
|
||||
* multiplied have length n, the "grade-school" algorithm has an
|
||||
* asymptotic complexity of O(n^2). In contrast, the Karatsuba algorithm
|
||||
* has complexity of O(n^(log2(3))), or O(n^1.585). It achieves this
|
||||
* increased performance by doing 3 multiplies instead of 4 when
|
||||
* evaluating the product. As it has some overhead, should be used when
|
||||
* both numbers are larger than a certain threshold (found
|
||||
* experimentally).
|
||||
*
|
||||
* See: http://en.wikipedia.org/wiki/Karatsuba_algorithm
|
||||
*/
|
||||
private static BigInteger multiplyKaratsuba(BigInteger x, BigInteger y)
|
||||
{
|
||||
int xlen = x.mag.length;
|
||||
int ylen = y.mag.length;
|
||||
|
||||
// The number of ints in each half of the number.
|
||||
int half = (Math.max(xlen, ylen)+1) / 2;
|
||||
|
||||
// xl and yl are the lower halves of x and y respectively,
|
||||
// xh and yh are the upper halves.
|
||||
BigInteger xl = x.getLower(half);
|
||||
BigInteger xh = x.getUpper(half);
|
||||
BigInteger yl = y.getLower(half);
|
||||
BigInteger yh = y.getUpper(half);
|
||||
|
||||
BigInteger p1 = xh.multiply(yh); // p1 = xh*yh
|
||||
BigInteger p2 = xl.multiply(yl); // p2 = xl*yl
|
||||
|
||||
// p3=(xh+xl)*(yh+yl)
|
||||
BigInteger p3 = xh.add(xl).multiply(yh.add(yl));
|
||||
|
||||
// result = p1 * 2^(32*2*half) + (p3 - p1 - p2) * 2^(32*half) + p2
|
||||
BigInteger result = p1.shiftLeft(32*half).add(p3.subtract(p1).subtract(p2)).shiftLeft(32*half).add(p2);
|
||||
|
||||
if (x.signum != y.signum)
|
||||
return result.negate();
|
||||
else
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies two BigIntegers using a 3-way Toom-Cook multiplication
|
||||
* algorithm. This is a recursive divide-and-conquer algorithm which is
|
||||
* more efficient for large numbers than what is commonly called the
|
||||
* "grade-school" algorithm used in multiplyToLen. If the numbers to be
|
||||
* multiplied have length n, the "grade-school" algorithm has an
|
||||
* asymptotic complexity of O(n^2). In contrast, 3-way Toom-Cook has a
|
||||
* complexity of about O(n^1.465). It achieves this increased asymptotic
|
||||
* performance by breaking each number into three parts and by doing 5
|
||||
* multiplies instead of 9 when evaluating the product. Due to overhead
|
||||
* (additions, shifts, and one division) in the Toom-Cook algorithm, it
|
||||
* should only be used when both numbers are larger than a certain
|
||||
* threshold (found experimentally). This threshold is generally larger
|
||||
* than that for Karatsuba multiplication, so this algorithm is generally
|
||||
* only used when numbers become significantly larger.
|
||||
*
|
||||
* The algorithm used is the "optimal" 3-way Toom-Cook algorithm outlined
|
||||
* by Marco Bodrato.
|
||||
*
|
||||
* See: http://bodrato.it/toom-cook/
|
||||
* http://bodrato.it/papers/#WAIFI2007
|
||||
*
|
||||
* "Towards Optimal Toom-Cook Multiplication for Univariate and
|
||||
* Multivariate Polynomials in Characteristic 2 and 0." by Marco BODRATO;
|
||||
* In C.Carlet and B.Sunar, Eds., "WAIFI'07 proceedings", p. 116-133,
|
||||
* LNCS #4547. Springer, Madrid, Spain, June 21-22, 2007.
|
||||
*
|
||||
*/
|
||||
private static BigInteger multiplyToomCook3(BigInteger a, BigInteger b)
|
||||
{
|
||||
int alen = a.mag.length;
|
||||
int blen = b.mag.length;
|
||||
|
||||
int largest = Math.max(alen, blen);
|
||||
|
||||
// k is the size (in ints) of the lower-order slices.
|
||||
int k = (largest+2)/3; // Equal to ceil(largest/3)
|
||||
|
||||
// r is the size (in ints) of the highest-order slice.
|
||||
int r = largest - 2*k;
|
||||
|
||||
// Obtain slices of the numbers. a2 and b2 are the most significant
|
||||
// bits of the numbers a and b, and a0 and b0 the least significant.
|
||||
BigInteger a0, a1, a2, b0, b1, b2;
|
||||
a2 = a.getToomSlice(k, r, 0, largest);
|
||||
a1 = a.getToomSlice(k, r, 1, largest);
|
||||
a0 = a.getToomSlice(k, r, 2, largest);
|
||||
b2 = b.getToomSlice(k, r, 0, largest);
|
||||
b1 = b.getToomSlice(k, r, 1, largest);
|
||||
b0 = b.getToomSlice(k, r, 2, largest);
|
||||
|
||||
BigInteger v0, v1, v2, vm1, vinf, t1, t2, tm1, da1, db1;
|
||||
|
||||
v0 = a0.multiply(b0);
|
||||
da1 = a2.add(a0);
|
||||
db1 = b2.add(b0);
|
||||
vm1 = da1.subtract(a1).multiply(db1.subtract(b1));
|
||||
da1 = da1.add(a1);
|
||||
db1 = db1.add(b1);
|
||||
v1 = da1.multiply(db1);
|
||||
v2 = da1.add(a2).shiftLeft(1).subtract(a0).multiply(
|
||||
db1.add(b2).shiftLeft(1).subtract(b0));
|
||||
vinf = a2.multiply(b2);
|
||||
|
||||
/* The algorithm requires two divisions by 2 and one by 3.
|
||||
All divisions are known to be exact, that is, they do not produce
|
||||
remainders, and all results are positive. The divisions by 2 are
|
||||
implemented as right shifts which are relatively efficient, leaving
|
||||
only an exact division by 3, which is done by a specialized
|
||||
linear-time algorithm. */
|
||||
t2 = v2.subtract(vm1).exactDivideBy3();
|
||||
tm1 = v1.subtract(vm1).shiftRight(1);
|
||||
t1 = v1.subtract(v0);
|
||||
t2 = t2.subtract(t1).shiftRight(1);
|
||||
t1 = t1.subtract(tm1).subtract(vinf);
|
||||
t2 = t2.subtract(vinf.shiftLeft(1));
|
||||
tm1 = tm1.subtract(t2);
|
||||
|
||||
// Number of bits to shift left.
|
||||
int ss = k*32;
|
||||
|
||||
BigInteger result = vinf.shiftLeft(ss).add(t2).shiftLeft(ss).add(t1).shiftLeft(ss).add(tm1).shiftLeft(ss).add(v0);
|
||||
|
||||
if (a.signum != b.signum)
|
||||
return result.negate();
|
||||
else
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a slice of a BigInteger for use in Toom-Cook multiplication.
|
||||
*
|
||||
* @param lowerSize The size of the lower-order bit slices.
|
||||
* @param upperSize The size of the higher-order bit slices.
|
||||
* @param slice The index of which slice is requested, which must be a
|
||||
* number from 0 to size-1. Slice 0 is the highest-order bits, and slice
|
||||
* size-1 are the lowest-order bits. Slice 0 may be of different size than
|
||||
* the other slices.
|
||||
* @param fullsize The size of the larger integer array, used to align
|
||||
* slices to the appropriate position when multiplying different-sized
|
||||
* numbers.
|
||||
*/
|
||||
private BigInteger getToomSlice(int lowerSize, int upperSize, int slice,
|
||||
int fullsize)
|
||||
{
|
||||
int start, end, sliceSize, len, offset;
|
||||
|
||||
len = mag.length;
|
||||
offset = fullsize - len;
|
||||
|
||||
if (slice == 0)
|
||||
{
|
||||
start = 0 - offset;
|
||||
end = upperSize - 1 - offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
start = upperSize + (slice-1)*lowerSize - offset;
|
||||
end = start + lowerSize - 1;
|
||||
}
|
||||
|
||||
if (start < 0)
|
||||
start = 0;
|
||||
if (end < 0)
|
||||
return ZERO;
|
||||
|
||||
sliceSize = (end-start) + 1;
|
||||
|
||||
if (sliceSize <= 0)
|
||||
return ZERO;
|
||||
|
||||
// While performing Toom-Cook, all slices are positive and
|
||||
// the sign is adjusted when the final number is composed.
|
||||
if (start==0 && sliceSize >= len)
|
||||
return this.abs();
|
||||
|
||||
int intSlice[] = new int[sliceSize];
|
||||
System.arraycopy(mag, start, intSlice, 0, sliceSize);
|
||||
|
||||
return new BigInteger(trustedStripLeadingZeroInts(intSlice), 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Does an exact division (that is, the remainder is known to be zero)
|
||||
* of the specified number by 3. This is used in Toom-Cook
|
||||
* multiplication. This is an efficient algorithm that runs in linear
|
||||
* time. If the argument is not exactly divisible by 3, results are
|
||||
* undefined. Note that this is expected to be called with positive
|
||||
* arguments only.
|
||||
*/
|
||||
private BigInteger exactDivideBy3()
|
||||
{
|
||||
int len = mag.length;
|
||||
int[] result = new int[len];
|
||||
long x, w, q, borrow;
|
||||
borrow = 0L;
|
||||
for (int i=len-1; i>=0; i--)
|
||||
{
|
||||
x = (mag[i] & LONG_MASK);
|
||||
w = x - borrow;
|
||||
if (borrow > x) // Did we make the number go negative?
|
||||
borrow = 1L;
|
||||
else
|
||||
borrow = 0L;
|
||||
|
||||
// 0xAAAAAAAB is the modular inverse of 3 (mod 2^32). Thus,
|
||||
// the effect of this is to divide by 3 (mod 2^32).
|
||||
// This is much faster than division on most architectures.
|
||||
q = (w * 0xAAAAAAABL) & LONG_MASK;
|
||||
result[i] = (int) q;
|
||||
|
||||
// Now check the borrow. The second check can of course be
|
||||
// eliminated if the first fails.
|
||||
if (q >= 0x55555556L)
|
||||
{
|
||||
borrow++;
|
||||
if (q >= 0xAAAAAAABL)
|
||||
borrow++;
|
||||
}
|
||||
}
|
||||
result = trustedStripLeadingZeroInts(result);
|
||||
return new BigInteger(result, signum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new BigInteger representing n lower ints of the number.
|
||||
* This is used by Karatsuba multiplication and Karatsuba squaring.
|
||||
*/
|
||||
private BigInteger getLower(int n) {
|
||||
int len = mag.length;
|
||||
|
||||
if (len <= n)
|
||||
return this;
|
||||
|
||||
int lowerInts[] = new int[n];
|
||||
System.arraycopy(mag, len-n, lowerInts, 0, n);
|
||||
|
||||
return new BigInteger(trustedStripLeadingZeroInts(lowerInts), 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new BigInteger representing mag.length-n upper
|
||||
* ints of the number. This is used by Karatsuba multiplication and
|
||||
* Karatsuba squaring.
|
||||
*/
|
||||
private BigInteger getUpper(int n) {
|
||||
int len = mag.length;
|
||||
|
||||
if (len <= n)
|
||||
return ZERO;
|
||||
|
||||
int upperLen = len - n;
|
||||
int upperInts[] = new int[upperLen];
|
||||
System.arraycopy(mag, 0, upperInts, 0, upperLen);
|
||||
|
||||
return new BigInteger(trustedStripLeadingZeroInts(upperInts), 1);
|
||||
}
|
||||
|
||||
// Squaring
|
||||
|
||||
/**
|
||||
* Returns a BigInteger whose value is {@code (this<sup>2</sup>)}.
|
||||
*
|
||||
@ -1409,8 +1730,18 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
|
||||
private BigInteger square() {
|
||||
if (signum == 0)
|
||||
return ZERO;
|
||||
int[] z = squareToLen(mag, mag.length, null);
|
||||
return new BigInteger(trustedStripLeadingZeroInts(z), 1);
|
||||
int len = mag.length;
|
||||
|
||||
if (len < KARATSUBA_SQUARE_THRESHOLD)
|
||||
{
|
||||
int[] z = squareToLen(mag, len, null);
|
||||
return new BigInteger(trustedStripLeadingZeroInts(z), 1);
|
||||
}
|
||||
else
|
||||
if (len < TOOM_COOK_SQUARE_THRESHOLD)
|
||||
return squareKaratsuba();
|
||||
else
|
||||
return squareToomCook3();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1480,6 +1811,83 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
|
||||
return z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Squares a BigInteger using the Karatsuba squaring algorithm. It should
|
||||
* be used when both numbers are larger than a certain threshold (found
|
||||
* experimentally). It is a recursive divide-and-conquer algorithm that
|
||||
* has better asymptotic performance than the algorithm used in
|
||||
* squareToLen.
|
||||
*/
|
||||
private BigInteger squareKaratsuba()
|
||||
{
|
||||
int half = (mag.length+1) / 2;
|
||||
|
||||
BigInteger xl = getLower(half);
|
||||
BigInteger xh = getUpper(half);
|
||||
|
||||
BigInteger xhs = xh.square(); // xhs = xh^2
|
||||
BigInteger xls = xl.square(); // xls = xl^2
|
||||
|
||||
// xh^2 << 64 + (((xl+xh)^2 - (xh^2 + xl^2)) << 32) + xl^2
|
||||
return xhs.shiftLeft(half*32).add(xl.add(xh).square().subtract(xhs.add(xls))).shiftLeft(half*32).add(xls);
|
||||
}
|
||||
|
||||
/**
|
||||
* Squares a BigInteger using the 3-way Toom-Cook squaring algorithm. It
|
||||
* should be used when both numbers are larger than a certain threshold
|
||||
* (found experimentally). It is a recursive divide-and-conquer algorithm
|
||||
* that has better asymptotic performance than the algorithm used in
|
||||
* squareToLen or squareKaratsuba.
|
||||
*/
|
||||
private BigInteger squareToomCook3()
|
||||
{
|
||||
int len = mag.length;
|
||||
|
||||
// k is the size (in ints) of the lower-order slices.
|
||||
int k = (len+2)/3; // Equal to ceil(largest/3)
|
||||
|
||||
// r is the size (in ints) of the highest-order slice.
|
||||
int r = len - 2*k;
|
||||
|
||||
// Obtain slices of the numbers. a2 is the most significant
|
||||
// bits of the number, and a0 the least significant.
|
||||
BigInteger a0, a1, a2;
|
||||
a2 = getToomSlice(k, r, 0, len);
|
||||
a1 = getToomSlice(k, r, 1, len);
|
||||
a0 = getToomSlice(k, r, 2, len);
|
||||
BigInteger v0, v1, v2, vm1, vinf, t1, t2, tm1, da1;
|
||||
|
||||
v0 = a0.square();
|
||||
da1 = a2.add(a0);
|
||||
vm1 = da1.subtract(a1).square();
|
||||
da1 = da1.add(a1);
|
||||
v1 = da1.square();
|
||||
vinf = a2.square();
|
||||
v2 = da1.add(a2).shiftLeft(1).subtract(a0).square();
|
||||
|
||||
/* The algorithm requires two divisions by 2 and one by 3.
|
||||
All divisions are known to be exact, that is, they do not produce
|
||||
remainders, and all results are positive. The divisions by 2 are
|
||||
implemented as right shifts which are relatively efficient, leaving
|
||||
only a division by 3.
|
||||
The division by 3 is done by an optimized algorithm for this case.
|
||||
*/
|
||||
t2 = v2.subtract(vm1).exactDivideBy3();
|
||||
tm1 = v1.subtract(vm1).shiftRight(1);
|
||||
t1 = v1.subtract(v0);
|
||||
t2 = t2.subtract(t1).shiftRight(1);
|
||||
t1 = t1.subtract(tm1).subtract(vinf);
|
||||
t2 = t2.subtract(vinf.shiftLeft(1));
|
||||
tm1 = tm1.subtract(t2);
|
||||
|
||||
// Number of bits to shift left.
|
||||
int ss = k*32;
|
||||
|
||||
return vinf.shiftLeft(ss).add(t2).shiftLeft(ss).add(t1).shiftLeft(ss).add(tm1).shiftLeft(ss).add(v0);
|
||||
}
|
||||
|
||||
// Division
|
||||
|
||||
/**
|
||||
* Returns a BigInteger whose value is {@code (this / val)}.
|
||||
*
|
||||
@ -1549,23 +1957,100 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
|
||||
if (signum==0)
|
||||
return (exponent==0 ? ONE : this);
|
||||
|
||||
// Perform exponentiation using repeated squaring trick
|
||||
int newSign = (signum<0 && (exponent&1)==1 ? -1 : 1);
|
||||
int[] baseToPow2 = this.mag;
|
||||
int[] result = {1};
|
||||
BigInteger partToSquare = this.abs();
|
||||
|
||||
while (exponent != 0) {
|
||||
if ((exponent & 1)==1) {
|
||||
result = multiplyToLen(result, result.length,
|
||||
baseToPow2, baseToPow2.length, null);
|
||||
result = trustedStripLeadingZeroInts(result);
|
||||
}
|
||||
if ((exponent >>>= 1) != 0) {
|
||||
baseToPow2 = squareToLen(baseToPow2, baseToPow2.length, null);
|
||||
baseToPow2 = trustedStripLeadingZeroInts(baseToPow2);
|
||||
}
|
||||
// Factor out powers of two from the base, as the exponentiation of
|
||||
// these can be done by left shifts only.
|
||||
// The remaining part can then be exponentiated faster. The
|
||||
// powers of two will be multiplied back at the end.
|
||||
int powersOfTwo = partToSquare.getLowestSetBit();
|
||||
|
||||
int remainingBits;
|
||||
|
||||
// Factor the powers of two out quickly by shifting right, if needed.
|
||||
if (powersOfTwo > 0)
|
||||
{
|
||||
partToSquare = partToSquare.shiftRight(powersOfTwo);
|
||||
remainingBits = partToSquare.bitLength();
|
||||
if (remainingBits == 1) // Nothing left but +/- 1?
|
||||
if (signum<0 && (exponent&1)==1)
|
||||
return NEGATIVE_ONE.shiftLeft(powersOfTwo*exponent);
|
||||
else
|
||||
return ONE.shiftLeft(powersOfTwo*exponent);
|
||||
}
|
||||
else
|
||||
{
|
||||
remainingBits = partToSquare.bitLength();
|
||||
if (remainingBits == 1) // Nothing left but +/- 1?
|
||||
if (signum<0 && (exponent&1)==1)
|
||||
return NEGATIVE_ONE;
|
||||
else
|
||||
return ONE;
|
||||
}
|
||||
|
||||
// This is a quick way to approximate the size of the result,
|
||||
// similar to doing log2[n] * exponent. This will give an upper bound
|
||||
// of how big the result can be, and which algorithm to use.
|
||||
int scaleFactor = remainingBits * exponent;
|
||||
|
||||
// Use slightly different algorithms for small and large operands.
|
||||
// See if the result will safely fit into a long. (Largest 2^63-1)
|
||||
if (partToSquare.mag.length==1 && scaleFactor <= 62)
|
||||
{
|
||||
// Small number algorithm. Everything fits into a long.
|
||||
int newSign = (signum<0 && (exponent&1)==1 ? -1 : 1);
|
||||
long result = 1;
|
||||
long baseToPow2 = partToSquare.mag[0] & LONG_MASK;
|
||||
|
||||
int workingExponent = exponent;
|
||||
|
||||
// Perform exponentiation using repeated squaring trick
|
||||
while (workingExponent != 0) {
|
||||
if ((workingExponent & 1)==1)
|
||||
result = result * baseToPow2;
|
||||
|
||||
if ((workingExponent >>>= 1) != 0)
|
||||
baseToPow2 = baseToPow2 * baseToPow2;
|
||||
}
|
||||
|
||||
// Multiply back the powers of two (quickly, by shifting left)
|
||||
if (powersOfTwo > 0)
|
||||
{
|
||||
int bitsToShift = powersOfTwo*exponent;
|
||||
if (bitsToShift + scaleFactor <= 62) // Fits in long?
|
||||
return valueOf((result << bitsToShift) * newSign);
|
||||
else
|
||||
return valueOf(result*newSign).shiftLeft(bitsToShift);
|
||||
}
|
||||
else
|
||||
return valueOf(result*newSign);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Large number algorithm. This is basically identical to
|
||||
// the algorithm above, but calls multiply() and square()
|
||||
// which may use more efficient algorithms for large numbers.
|
||||
BigInteger answer = ONE;
|
||||
|
||||
int workingExponent = exponent;
|
||||
// Perform exponentiation using repeated squaring trick
|
||||
while (workingExponent != 0) {
|
||||
if ((workingExponent & 1)==1)
|
||||
answer = answer.multiply(partToSquare);
|
||||
|
||||
if ((workingExponent >>>= 1) != 0)
|
||||
partToSquare = partToSquare.square();
|
||||
}
|
||||
// Multiply back the (exponentiated) powers of two (quickly,
|
||||
// by shifting left)
|
||||
if (powersOfTwo > 0)
|
||||
answer = answer.shiftLeft(powersOfTwo*exponent);
|
||||
|
||||
if (signum<0 && (exponent&1)==1)
|
||||
return answer.negate();
|
||||
else
|
||||
return answer;
|
||||
}
|
||||
return new BigInteger(result, newSign);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2117,7 +2602,7 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
|
||||
* Perform exponentiation using repeated squaring trick, chopping off
|
||||
* high order bits as indicated by modulus.
|
||||
*/
|
||||
BigInteger result = valueOf(1);
|
||||
BigInteger result = ONE;
|
||||
BigInteger baseToPow2 = this.mod2(p);
|
||||
int expOffset = 0;
|
||||
|
||||
@ -2850,6 +3335,7 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
|
||||
/* zero[i] is a string of i consecutive zeros. */
|
||||
private static String zeros[] = new String[64];
|
||||
static {
|
||||
@ -3218,21 +3704,21 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
|
||||
* little-endian binary representation of the magnitude (int 0 is the
|
||||
* least significant). If the magnitude is zero, return value is undefined.
|
||||
*/
|
||||
private int firstNonzeroIntNum() {
|
||||
int fn = firstNonzeroIntNum - 2;
|
||||
if (fn == -2) { // firstNonzeroIntNum not initialized yet
|
||||
fn = 0;
|
||||
private int firstNonzeroIntNum() {
|
||||
int fn = firstNonzeroIntNum - 2;
|
||||
if (fn == -2) { // firstNonzeroIntNum not initialized yet
|
||||
fn = 0;
|
||||
|
||||
// Search for the first nonzero int
|
||||
int i;
|
||||
int mlen = mag.length;
|
||||
for (i = mlen - 1; i >= 0 && mag[i] == 0; i--)
|
||||
;
|
||||
fn = mlen - i - 1;
|
||||
firstNonzeroIntNum = fn + 2; // offset by two to initialize
|
||||
}
|
||||
return fn;
|
||||
}
|
||||
// Search for the first nonzero int
|
||||
int i;
|
||||
int mlen = mag.length;
|
||||
for (i = mlen - 1; i >= 0 && mag[i] == 0; i--)
|
||||
;
|
||||
fn = mlen - i - 1;
|
||||
firstNonzeroIntNum = fn + 2; // offset by two to initialize
|
||||
}
|
||||
return fn;
|
||||
}
|
||||
|
||||
/** use serialVersionUID from JDK 1.1. for interoperability */
|
||||
private static final long serialVersionUID = -8287574255936472291L;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -23,15 +23,19 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 4181191 4161971 4227146 4194389 4823171 4624738 4812225
|
||||
* @bug 4181191 4161971 4227146 4194389 4823171 4624738 4812225 4837946
|
||||
* @summary tests methods in BigInteger
|
||||
* @run main/timeout=400 BigIntegerTest
|
||||
* @author madbot
|
||||
*/
|
||||
|
||||
import java.util.Random;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.io.*;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* This is a simple test class created to ensure that the results
|
||||
@ -48,21 +52,42 @@ import java.io.*;
|
||||
*
|
||||
*/
|
||||
public class BigIntegerTest {
|
||||
//
|
||||
// Bit large number thresholds based on the int thresholds
|
||||
// defined in BigInteger itself:
|
||||
//
|
||||
// KARATSUBA_THRESHOLD = 50 ints = 1600 bits
|
||||
// TOOM_COOK_THRESHOLD = 75 ints = 2400 bits
|
||||
// KARATSUBA_SQUARE_THRESHOLD = 90 ints = 2880 bits
|
||||
// TOOM_COOK_SQUARE_THRESHOLD = 140 ints = 4480 bits
|
||||
//
|
||||
static final int BITS_KARATSUBA = 1600;
|
||||
static final int BITS_TOOM_COOK = 2400;
|
||||
static final int BITS_KARATSUBA_SQUARE = 2880;
|
||||
static final int BITS_TOOM_COOK_SQUARE = 4480;
|
||||
|
||||
static final int ORDER_SMALL = 60;
|
||||
static final int ORDER_MEDIUM = 100;
|
||||
// #bits for testing Karatsuba and Burnikel-Ziegler
|
||||
static final int ORDER_KARATSUBA = 1800;
|
||||
// #bits for testing Toom-Cook
|
||||
static final int ORDER_TOOM_COOK = 3000;
|
||||
// #bits for testing Karatsuba squaring
|
||||
static final int ORDER_KARATSUBA_SQUARE = 3200;
|
||||
// #bits for testing Toom-Cook squaring
|
||||
static final int ORDER_TOOM_COOK_SQUARE = 4600;
|
||||
|
||||
static Random rnd = new Random();
|
||||
static int size = 1000; // numbers per batch
|
||||
static boolean failure = false;
|
||||
|
||||
// Some variables for sizing test numbers in bits
|
||||
private static int order1 = 100;
|
||||
private static int order2 = 60;
|
||||
private static int order3 = 30;
|
||||
|
||||
public static void pow() {
|
||||
public static void pow(int order) {
|
||||
int failCount1 = 0;
|
||||
|
||||
for (int i=0; i<size; i++) {
|
||||
int power = rnd.nextInt(6) +2;
|
||||
BigInteger x = fetchNumber(order1);
|
||||
// Test identity x^power == x*x*x ... *x
|
||||
int power = rnd.nextInt(6) + 2;
|
||||
BigInteger x = fetchNumber(order);
|
||||
BigInteger y = x.pow(power);
|
||||
BigInteger z = x;
|
||||
|
||||
@ -72,22 +97,39 @@ public class BigIntegerTest {
|
||||
if (!y.equals(z))
|
||||
failCount1++;
|
||||
}
|
||||
report("pow", failCount1);
|
||||
report("pow for " + order + " bits", failCount1);
|
||||
}
|
||||
|
||||
public static void arithmetic() {
|
||||
public static void square(int order) {
|
||||
int failCount1 = 0;
|
||||
|
||||
for (int i=0; i<size; i++) {
|
||||
// Test identity x^2 == x*x
|
||||
BigInteger x = fetchNumber(order);
|
||||
BigInteger xx = x.multiply(x);
|
||||
BigInteger x2 = x.pow(2);
|
||||
|
||||
if (!x2.equals(xx))
|
||||
failCount1++;
|
||||
}
|
||||
report("square for " + order + " bits", failCount1);
|
||||
}
|
||||
|
||||
public static void arithmetic(int order) {
|
||||
int failCount = 0;
|
||||
|
||||
for (int i=0; i<size; i++) {
|
||||
BigInteger x = fetchNumber(order1);
|
||||
BigInteger x = fetchNumber(order);
|
||||
while(x.compareTo(BigInteger.ZERO) != 1)
|
||||
x = fetchNumber(order1);
|
||||
BigInteger y = fetchNumber(order1/2);
|
||||
x = fetchNumber(order);
|
||||
BigInteger y = fetchNumber(order/2);
|
||||
while(x.compareTo(y) == -1)
|
||||
y = fetchNumber(order1/2);
|
||||
y = fetchNumber(order/2);
|
||||
if (y.equals(BigInteger.ZERO))
|
||||
y = y.add(BigInteger.ONE);
|
||||
|
||||
// Test identity ((x/y))*y + x%y - x == 0
|
||||
// using separate divide() and remainder()
|
||||
BigInteger baz = x.divide(y);
|
||||
baz = baz.multiply(y);
|
||||
baz = baz.add(x.remainder(y));
|
||||
@ -95,19 +137,21 @@ public class BigIntegerTest {
|
||||
if (!baz.equals(BigInteger.ZERO))
|
||||
failCount++;
|
||||
}
|
||||
report("Arithmetic I", failCount);
|
||||
report("Arithmetic I for " + order + " bits", failCount);
|
||||
|
||||
failCount = 0;
|
||||
for (int i=0; i<100; i++) {
|
||||
BigInteger x = fetchNumber(order1);
|
||||
BigInteger x = fetchNumber(order);
|
||||
while(x.compareTo(BigInteger.ZERO) != 1)
|
||||
x = fetchNumber(order1);
|
||||
BigInteger y = fetchNumber(order1/2);
|
||||
x = fetchNumber(order);
|
||||
BigInteger y = fetchNumber(order/2);
|
||||
while(x.compareTo(y) == -1)
|
||||
y = fetchNumber(order1/2);
|
||||
y = fetchNumber(order/2);
|
||||
if (y.equals(BigInteger.ZERO))
|
||||
y = y.add(BigInteger.ONE);
|
||||
|
||||
// Test identity ((x/y))*y + x%y - x == 0
|
||||
// using divideAndRemainder()
|
||||
BigInteger baz[] = x.divideAndRemainder(y);
|
||||
baz[0] = baz[0].multiply(y);
|
||||
baz[0] = baz[0].add(baz[1]);
|
||||
@ -115,7 +159,118 @@ public class BigIntegerTest {
|
||||
if (!baz[0].equals(BigInteger.ZERO))
|
||||
failCount++;
|
||||
}
|
||||
report("Arithmetic II", failCount);
|
||||
report("Arithmetic II for " + order + " bits", failCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanity test for Karatsuba and 3-way Toom-Cook multiplication.
|
||||
* For each of the Karatsuba and 3-way Toom-Cook multiplication thresholds,
|
||||
* construct two factors each with a mag array one element shorter than the
|
||||
* threshold, and with the most significant bit set and the rest of the bits
|
||||
* random. Each of these numbers will therefore be below the threshold but
|
||||
* if shifted left be above the threshold. Call the numbers 'u' and 'v' and
|
||||
* define random shifts 'a' and 'b' in the range [1,32]. Then we have the
|
||||
* identity
|
||||
* <pre>
|
||||
* (u << a)*(v << b) = (u*v) << (a + b)
|
||||
* </pre>
|
||||
* For Karatsuba multiplication, the right hand expression will be evaluated
|
||||
* using the standard naive algorithm, and the left hand expression using
|
||||
* the Karatsuba algorithm. For 3-way Toom-Cook multiplication, the right
|
||||
* hand expression will be evaluated using Karatsuba multiplication, and the
|
||||
* left hand expression using 3-way Toom-Cook multiplication.
|
||||
*/
|
||||
public static void multiplyLarge() {
|
||||
int failCount = 0;
|
||||
|
||||
BigInteger base = BigInteger.ONE.shiftLeft(BITS_KARATSUBA - 32 - 1);
|
||||
for (int i=0; i<size; i++) {
|
||||
BigInteger x = fetchNumber(BITS_KARATSUBA - 32 - 1);
|
||||
BigInteger u = base.add(x);
|
||||
int a = 1 + rnd.nextInt(31);
|
||||
BigInteger w = u.shiftLeft(a);
|
||||
|
||||
BigInteger y = fetchNumber(BITS_KARATSUBA - 32 - 1);
|
||||
BigInteger v = base.add(y);
|
||||
int b = 1 + rnd.nextInt(32);
|
||||
BigInteger z = v.shiftLeft(b);
|
||||
|
||||
BigInteger multiplyResult = u.multiply(v).shiftLeft(a + b);
|
||||
BigInteger karatsubaMultiplyResult = w.multiply(z);
|
||||
|
||||
if (!multiplyResult.equals(karatsubaMultiplyResult)) {
|
||||
failCount++;
|
||||
}
|
||||
}
|
||||
|
||||
report("multiplyLarge Karatsuba", failCount);
|
||||
|
||||
failCount = 0;
|
||||
base = base.shiftLeft(BITS_TOOM_COOK - BITS_KARATSUBA);
|
||||
for (int i=0; i<size; i++) {
|
||||
BigInteger x = fetchNumber(BITS_TOOM_COOK - 32 - 1);
|
||||
BigInteger u = base.add(x);
|
||||
BigInteger u2 = u.shiftLeft(1);
|
||||
BigInteger y = fetchNumber(BITS_TOOM_COOK - 32 - 1);
|
||||
BigInteger v = base.add(y);
|
||||
BigInteger v2 = v.shiftLeft(1);
|
||||
|
||||
BigInteger multiplyResult = u.multiply(v).shiftLeft(2);
|
||||
BigInteger toomCookMultiplyResult = u2.multiply(v2);
|
||||
|
||||
if (!multiplyResult.equals(toomCookMultiplyResult)) {
|
||||
failCount++;
|
||||
}
|
||||
}
|
||||
|
||||
report("multiplyLarge Toom-Cook", failCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanity test for Karatsuba and 3-way Toom-Cook squaring.
|
||||
* This test is analogous to {@link AbstractMethodError#multiplyLarge}
|
||||
* with both factors being equal. The squaring methods will not be tested
|
||||
* unless the <code>bigInteger.multiply(bigInteger)</code> tests whether
|
||||
* the parameter is the same instance on which the method is being invoked
|
||||
* and calls <code>square()</code> accordingly.
|
||||
*/
|
||||
public static void squareLarge() {
|
||||
int failCount = 0;
|
||||
|
||||
BigInteger base = BigInteger.ONE.shiftLeft(BITS_KARATSUBA_SQUARE - 32 - 1);
|
||||
for (int i=0; i<size; i++) {
|
||||
BigInteger x = fetchNumber(BITS_KARATSUBA_SQUARE - 32 - 1);
|
||||
BigInteger u = base.add(x);
|
||||
int a = 1 + rnd.nextInt(31);
|
||||
BigInteger w = u.shiftLeft(a);
|
||||
|
||||
BigInteger squareResult = u.multiply(u).shiftLeft(2*a);
|
||||
BigInteger karatsubaSquareResult = w.multiply(w);
|
||||
|
||||
if (!squareResult.equals(karatsubaSquareResult)) {
|
||||
failCount++;
|
||||
}
|
||||
}
|
||||
|
||||
report("squareLarge Karatsuba", failCount);
|
||||
|
||||
failCount = 0;
|
||||
base = base.shiftLeft(BITS_TOOM_COOK_SQUARE - BITS_KARATSUBA_SQUARE);
|
||||
for (int i=0; i<size; i++) {
|
||||
BigInteger x = fetchNumber(BITS_TOOM_COOK_SQUARE - 32 - 1);
|
||||
BigInteger u = base.add(x);
|
||||
int a = 1 + rnd.nextInt(31);
|
||||
BigInteger w = u.shiftLeft(a);
|
||||
|
||||
BigInteger squareResult = u.multiply(u).shiftLeft(2*a);
|
||||
BigInteger toomCookSquareResult = w.multiply(w);
|
||||
|
||||
if (!squareResult.equals(toomCookSquareResult)) {
|
||||
failCount++;
|
||||
}
|
||||
}
|
||||
|
||||
report("squareLarge Toom-Cook", failCount);
|
||||
}
|
||||
|
||||
public static void bitCount() {
|
||||
@ -160,14 +315,14 @@ public class BigIntegerTest {
|
||||
report("BitLength", failCount);
|
||||
}
|
||||
|
||||
public static void bitOps() {
|
||||
public static void bitOps(int order) {
|
||||
int failCount1 = 0, failCount2 = 0, failCount3 = 0;
|
||||
|
||||
for (int i=0; i<size*5; i++) {
|
||||
BigInteger x = fetchNumber(order1);
|
||||
BigInteger x = fetchNumber(order);
|
||||
BigInteger y;
|
||||
|
||||
/* Test setBit and clearBit (and testBit) */
|
||||
// Test setBit and clearBit (and testBit)
|
||||
if (x.signum() < 0) {
|
||||
y = BigInteger.valueOf(-1);
|
||||
for (int j=0; j<x.bitLength(); j++)
|
||||
@ -182,7 +337,7 @@ public class BigIntegerTest {
|
||||
if (!x.equals(y))
|
||||
failCount1++;
|
||||
|
||||
/* Test flipBit (and testBit) */
|
||||
// Test flipBit (and testBit)
|
||||
y = BigInteger.valueOf(x.signum()<0 ? -1 : 0);
|
||||
for (int j=0; j<x.bitLength(); j++)
|
||||
if (x.signum()<0 ^ x.testBit(j))
|
||||
@ -190,13 +345,13 @@ public class BigIntegerTest {
|
||||
if (!x.equals(y))
|
||||
failCount2++;
|
||||
}
|
||||
report("clearBit/testBit", failCount1);
|
||||
report("flipBit/testBit", failCount2);
|
||||
report("clearBit/testBit for " + order + " bits", failCount1);
|
||||
report("flipBit/testBit for " + order + " bits", failCount2);
|
||||
|
||||
for (int i=0; i<size*5; i++) {
|
||||
BigInteger x = fetchNumber(order1);
|
||||
BigInteger x = fetchNumber(order);
|
||||
|
||||
/* Test getLowestSetBit() */
|
||||
// Test getLowestSetBit()
|
||||
int k = x.getLowestSetBit();
|
||||
if (x.signum() == 0) {
|
||||
if (k != -1)
|
||||
@ -210,43 +365,43 @@ public class BigIntegerTest {
|
||||
failCount3++;
|
||||
}
|
||||
}
|
||||
report("getLowestSetBit", failCount3);
|
||||
report("getLowestSetBit for " + order + " bits", failCount3);
|
||||
}
|
||||
|
||||
public static void bitwise() {
|
||||
public static void bitwise(int order) {
|
||||
|
||||
/* Test identity x^y == x|y &~ x&y */
|
||||
// Test identity x^y == x|y &~ x&y
|
||||
int failCount = 0;
|
||||
for (int i=0; i<size; i++) {
|
||||
BigInteger x = fetchNumber(order1);
|
||||
BigInteger y = fetchNumber(order1);
|
||||
BigInteger x = fetchNumber(order);
|
||||
BigInteger y = fetchNumber(order);
|
||||
BigInteger z = x.xor(y);
|
||||
BigInteger w = x.or(y).andNot(x.and(y));
|
||||
if (!z.equals(w))
|
||||
failCount++;
|
||||
}
|
||||
report("Logic (^ | & ~)", failCount);
|
||||
report("Logic (^ | & ~) for " + order + " bits", failCount);
|
||||
|
||||
/* Test identity x &~ y == ~(~x | y) */
|
||||
// Test identity x &~ y == ~(~x | y)
|
||||
failCount = 0;
|
||||
for (int i=0; i<size; i++) {
|
||||
BigInteger x = fetchNumber(order1);
|
||||
BigInteger y = fetchNumber(order1);
|
||||
BigInteger x = fetchNumber(order);
|
||||
BigInteger y = fetchNumber(order);
|
||||
BigInteger z = x.andNot(y);
|
||||
BigInteger w = x.not().or(y).not();
|
||||
if (!z.equals(w))
|
||||
failCount++;
|
||||
}
|
||||
report("Logic (&~ | ~)", failCount);
|
||||
report("Logic (&~ | ~) for " + order + " bits", failCount);
|
||||
}
|
||||
|
||||
public static void shift() {
|
||||
public static void shift(int order) {
|
||||
int failCount1 = 0;
|
||||
int failCount2 = 0;
|
||||
int failCount3 = 0;
|
||||
|
||||
for (int i=0; i<100; i++) {
|
||||
BigInteger x = fetchNumber(order1);
|
||||
BigInteger x = fetchNumber(order);
|
||||
int n = Math.abs(rnd.nextInt()%200);
|
||||
|
||||
if (!x.shiftLeft(n).equals
|
||||
@ -274,18 +429,18 @@ public class BigIntegerTest {
|
||||
if (!x.shiftLeft(n).shiftRight(n).equals(x))
|
||||
failCount3++;
|
||||
}
|
||||
report("baz shiftLeft", failCount1);
|
||||
report("baz shiftRight", failCount2);
|
||||
report("baz shiftLeft/Right", failCount3);
|
||||
report("baz shiftLeft for " + order + " bits", failCount1);
|
||||
report("baz shiftRight for " + order + " bits", failCount2);
|
||||
report("baz shiftLeft/Right for " + order + " bits", failCount3);
|
||||
}
|
||||
|
||||
public static void divideAndRemainder() {
|
||||
public static void divideAndRemainder(int order) {
|
||||
int failCount1 = 0;
|
||||
|
||||
for (int i=0; i<size; i++) {
|
||||
BigInteger x = fetchNumber(order1).abs();
|
||||
BigInteger x = fetchNumber(order).abs();
|
||||
while(x.compareTo(BigInteger.valueOf(3L)) != 1)
|
||||
x = fetchNumber(order1).abs();
|
||||
x = fetchNumber(order).abs();
|
||||
BigInteger z = x.divide(BigInteger.valueOf(2L));
|
||||
BigInteger y[] = x.divideAndRemainder(x);
|
||||
if (!y[0].equals(BigInteger.ONE)) {
|
||||
@ -306,7 +461,7 @@ public class BigIntegerTest {
|
||||
System.err.println(" y :"+y);
|
||||
}
|
||||
}
|
||||
report("divideAndRemainder I", failCount1);
|
||||
report("divideAndRemainder for " + order + " bits", failCount1);
|
||||
}
|
||||
|
||||
public static void stringConv() {
|
||||
@ -331,13 +486,13 @@ public class BigIntegerTest {
|
||||
report("String Conversion", failCount);
|
||||
}
|
||||
|
||||
public static void byteArrayConv() {
|
||||
public static void byteArrayConv(int order) {
|
||||
int failCount = 0;
|
||||
|
||||
for (int i=0; i<size; i++) {
|
||||
BigInteger x = fetchNumber(order1);
|
||||
BigInteger x = fetchNumber(order);
|
||||
while (x.equals(BigInteger.ZERO))
|
||||
x = fetchNumber(order1);
|
||||
x = fetchNumber(order);
|
||||
BigInteger y = new BigInteger(x.toByteArray());
|
||||
if (!x.equals(y)) {
|
||||
failCount++;
|
||||
@ -345,19 +500,19 @@ public class BigIntegerTest {
|
||||
System.err.println("new is "+y);
|
||||
}
|
||||
}
|
||||
report("Array Conversion", failCount);
|
||||
report("Array Conversion for " + order + " bits", failCount);
|
||||
}
|
||||
|
||||
public static void modInv() {
|
||||
public static void modInv(int order) {
|
||||
int failCount = 0, successCount = 0, nonInvCount = 0;
|
||||
|
||||
for (int i=0; i<size; i++) {
|
||||
BigInteger x = fetchNumber(order1);
|
||||
BigInteger x = fetchNumber(order);
|
||||
while(x.equals(BigInteger.ZERO))
|
||||
x = fetchNumber(order1);
|
||||
BigInteger m = fetchNumber(order1).abs();
|
||||
x = fetchNumber(order);
|
||||
BigInteger m = fetchNumber(order).abs();
|
||||
while(m.compareTo(BigInteger.ONE) != 1)
|
||||
m = fetchNumber(order1).abs();
|
||||
m = fetchNumber(order).abs();
|
||||
|
||||
try {
|
||||
BigInteger inv = x.modInverse(m);
|
||||
@ -374,10 +529,10 @@ public class BigIntegerTest {
|
||||
nonInvCount++;
|
||||
}
|
||||
}
|
||||
report("Modular Inverse", failCount);
|
||||
report("Modular Inverse for " + order + " bits", failCount);
|
||||
}
|
||||
|
||||
public static void modExp() {
|
||||
public static void modExp(int order1, int order2) {
|
||||
int failCount = 0;
|
||||
|
||||
for (int i=0; i<size/10; i++) {
|
||||
@ -398,13 +553,14 @@ public class BigIntegerTest {
|
||||
failCount++;
|
||||
}
|
||||
}
|
||||
report("Exponentiation I", failCount);
|
||||
report("Exponentiation I for " + order1 + " and " +
|
||||
order2 + " bits", failCount);
|
||||
}
|
||||
|
||||
// This test is based on Fermat's theorem
|
||||
// which is not ideal because base must not be multiple of modulus
|
||||
// and modulus must be a prime or pseudoprime (Carmichael number)
|
||||
public static void modExp2() {
|
||||
public static void modExp2(int order) {
|
||||
int failCount = 0;
|
||||
|
||||
for (int i=0; i<10; i++) {
|
||||
@ -412,11 +568,11 @@ public class BigIntegerTest {
|
||||
while(m.compareTo(BigInteger.ONE) != 1)
|
||||
m = new BigInteger(100, 5, rnd);
|
||||
BigInteger exp = m.subtract(BigInteger.ONE);
|
||||
BigInteger base = fetchNumber(order1).abs();
|
||||
BigInteger base = fetchNumber(order).abs();
|
||||
while(base.compareTo(m) != -1)
|
||||
base = fetchNumber(order1).abs();
|
||||
base = fetchNumber(order).abs();
|
||||
while(base.equals(BigInteger.ZERO))
|
||||
base = fetchNumber(order1).abs();
|
||||
base = fetchNumber(order).abs();
|
||||
|
||||
BigInteger one = base.modPow(exp, m);
|
||||
if (!one.equals(BigInteger.ONE)) {
|
||||
@ -426,7 +582,7 @@ public class BigIntegerTest {
|
||||
failCount++;
|
||||
}
|
||||
}
|
||||
report("Exponentiation II", failCount);
|
||||
report("Exponentiation II for " + order + " bits", failCount);
|
||||
}
|
||||
|
||||
private static final int[] mersenne_powers = {
|
||||
@ -704,36 +860,62 @@ public class BigIntegerTest {
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
// Some variables for sizing test numbers in bits
|
||||
int order1 = ORDER_MEDIUM;
|
||||
int order2 = ORDER_SMALL;
|
||||
int order3 = ORDER_KARATSUBA;
|
||||
int order4 = ORDER_TOOM_COOK;
|
||||
|
||||
if (args.length >0)
|
||||
order1 = (int)((Integer.parseInt(args[0]))* 3.333);
|
||||
if (args.length >1)
|
||||
order2 = (int)((Integer.parseInt(args[1]))* 3.333);
|
||||
if (args.length >2)
|
||||
order3 = (int)((Integer.parseInt(args[2]))* 3.333);
|
||||
if (args.length >3)
|
||||
order4 = (int)((Integer.parseInt(args[3]))* 3.333);
|
||||
|
||||
prime();
|
||||
nextProbablePrime();
|
||||
|
||||
arithmetic();
|
||||
divideAndRemainder();
|
||||
pow();
|
||||
arithmetic(order1); // small numbers
|
||||
arithmetic(order3); // Karatsuba / Burnikel-Ziegler range
|
||||
arithmetic(order4); // Toom-Cook range
|
||||
|
||||
divideAndRemainder(order1); // small numbers
|
||||
divideAndRemainder(order3); // Karatsuba / Burnikel-Ziegler range
|
||||
divideAndRemainder(order4); // Toom-Cook range
|
||||
|
||||
pow(order1);
|
||||
pow(order3);
|
||||
pow(order4);
|
||||
|
||||
square(ORDER_MEDIUM);
|
||||
square(ORDER_KARATSUBA_SQUARE);
|
||||
square(ORDER_TOOM_COOK_SQUARE);
|
||||
|
||||
bitCount();
|
||||
bitLength();
|
||||
bitOps();
|
||||
bitwise();
|
||||
bitOps(order1);
|
||||
bitwise(order1);
|
||||
|
||||
shift();
|
||||
shift(order1);
|
||||
|
||||
byteArrayConv();
|
||||
byteArrayConv(order1);
|
||||
|
||||
modInv();
|
||||
modExp();
|
||||
modExp2();
|
||||
modInv(order1); // small numbers
|
||||
modInv(order3); // Karatsuba / Burnikel-Ziegler range
|
||||
modInv(order4); // Toom-Cook range
|
||||
|
||||
modExp(order1, order2);
|
||||
modExp2(order1);
|
||||
|
||||
stringConv();
|
||||
serialize();
|
||||
|
||||
multiplyLarge();
|
||||
squareLarge();
|
||||
|
||||
if (failure)
|
||||
throw new RuntimeException("Failure in BigIntegerTest.");
|
||||
}
|
||||
@ -747,7 +929,7 @@ public class BigIntegerTest {
|
||||
*/
|
||||
private static BigInteger fetchNumber(int order) {
|
||||
boolean negative = rnd.nextBoolean();
|
||||
int numType = rnd.nextInt(6);
|
||||
int numType = rnd.nextInt(7);
|
||||
BigInteger result = null;
|
||||
if (order < 2) order = 2;
|
||||
|
||||
@ -783,6 +965,19 @@ public class BigIntegerTest {
|
||||
result = result.or(temp);
|
||||
}
|
||||
break;
|
||||
case 5: // Runs of consecutive ones and zeros
|
||||
result = ZERO;
|
||||
int remaining = order;
|
||||
int bit = rnd.nextInt(2);
|
||||
while (remaining > 0) {
|
||||
int runLength = Math.min(remaining, rnd.nextInt(order));
|
||||
result = result.shiftLeft(runLength);
|
||||
if (bit > 0)
|
||||
result = result.add(ONE.shiftLeft(runLength).subtract(ONE));
|
||||
remaining -= runLength;
|
||||
bit = 1 - bit;
|
||||
}
|
||||
break;
|
||||
|
||||
default: // random bits
|
||||
result = new BigInteger(order, rnd);
|
||||
|
Loading…
x
Reference in New Issue
Block a user