Path: blob/master/test/jdk/java/math/BigInteger/BigIntegerTest.java
41149 views
/*1* Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @library /test/lib26* @build jdk.test.lib.RandomFactory27* @run main BigIntegerTest28* @bug 4181191 4161971 4227146 4194389 4823171 4624738 4812225 4837946 4026465 8074460 8078672 8032027 822984529* @summary tests methods in BigInteger (use -Dseed=X to set PRNG seed)30* @run main/timeout=400 BigIntegerTest31* @author madbot32* @key randomness33*/3435import java.io.File;36import java.io.FileInputStream;37import java.io.FileOutputStream;38import java.io.ObjectInputStream;39import java.io.ObjectOutputStream;40import java.math.BigDecimal;41import java.math.BigInteger;42import java.util.Random;43import java.util.function.ToIntFunction;44import java.util.stream.Collectors;45import java.util.stream.DoubleStream;46import java.util.stream.IntStream;47import java.util.stream.LongStream;48import java.util.stream.Stream;49import jdk.test.lib.RandomFactory;5051/**52* This is a simple test class created to ensure that the results53* generated by BigInteger adhere to certain identities. Passing54* this test is a strong assurance that the BigInteger operations55* are working correctly.56*57* Four arguments may be specified which give the number of58* decimal digits you desire in the four batches of test numbers.59*60* The tests are performed on arrays of random numbers which are61* generated by a Random class as well as special cases which62* throw in boundary numbers such as 0, 1, maximum sized, etc.63*64*/65public class BigIntegerTest {66//67// Bit large number thresholds based on the int thresholds68// defined in BigInteger itself:69//70// KARATSUBA_THRESHOLD = 80 ints = 2560 bits71// TOOM_COOK_THRESHOLD = 240 ints = 7680 bits72// KARATSUBA_SQUARE_THRESHOLD = 128 ints = 4096 bits73// TOOM_COOK_SQUARE_THRESHOLD = 216 ints = 6912 bits74//75// SCHOENHAGE_BASE_CONVERSION_THRESHOLD = 20 ints = 640 bits76//77// BURNIKEL_ZIEGLER_THRESHOLD = 80 ints = 2560 bits78//79static final int BITS_KARATSUBA = 2560;80static final int BITS_TOOM_COOK = 7680;81static final int BITS_KARATSUBA_SQUARE = 4096;82static final int BITS_TOOM_COOK_SQUARE = 6912;83static final int BITS_SCHOENHAGE_BASE = 640;84static final int BITS_BURNIKEL_ZIEGLER = 2560;85static final int BITS_BURNIKEL_ZIEGLER_OFFSET = 1280;8687static final int ORDER_SMALL = 60;88static final int ORDER_MEDIUM = 100;89// #bits for testing Karatsuba90static final int ORDER_KARATSUBA = 2760;91// #bits for testing Toom-Cook and Burnikel-Ziegler92static final int ORDER_TOOM_COOK = 8000;93// #bits for testing Karatsuba squaring94static final int ORDER_KARATSUBA_SQUARE = 4200;95// #bits for testing Toom-Cook squaring96static final int ORDER_TOOM_COOK_SQUARE = 7000;9798static final int SIZE = 1000; // numbers per batch99100private static Random random = RandomFactory.getRandom();101102static boolean failure = false;103104public static void constructor() {105int failCount = 0;106107// --- guard condition tests for array indexing ---108109int arrayLength = 23;110int halfLength = arrayLength/2;111byte[] array = new byte[arrayLength];112random.nextBytes(array);113114int[][] offLen = new int[][] { // offset, length, num exceptions115{-1, arrayLength, 1}, // negative offset116{0, arrayLength, 0}, // OK117{1, arrayLength, 1}, // length overflow118{arrayLength - 1, 1, 0}, // OK119{arrayLength, 1, 1}, // offset overflow120{0, -1, 1}, // negative length121{halfLength, arrayLength - halfLength + 1, 1} // length overflow122};123124// two's complement125for (int[] ol : offLen) {126int numExceptions = 0;127try {128BigInteger bi = new BigInteger(array, ol[0], ol[1]);129} catch (IndexOutOfBoundsException e) {130numExceptions++;131}132if (numExceptions != ol[2]) {133System.err.println("IndexOutOfBoundsException did not occur for "134+ " two's complement constructor with parameters offset "135+ ol[0] + " and length " + ol[1]);136failCount++;137}138}139140// sign-magnitude141for (int[] ol : offLen) {142int numExceptions = 0;143try {144BigInteger bi = new BigInteger(1, array, ol[0], ol[1]);145} catch (IndexOutOfBoundsException e) {146numExceptions++;147}148if (numExceptions != ol[2]) {149System.err.println("IndexOutOfBoundsException did not occur for "150+ " sign-magnitude constructor with parameters offset "151+ ol[0] + " and length " + ol[1]);152failCount++;153}154}155156// --- tests for creation of zero-valued BigIntegers ---157158byte[] magZeroLength = new byte[0];159for (int signum = -1; signum <= 1; signum++) {160BigInteger bi = new BigInteger(signum, magZeroLength);161if (bi.compareTo(BigInteger.ZERO) != 0) {162System.err.println("A: Zero length BigInteger != 0 for signum " + signum);163failCount++;164}165}166167for (int signum = -1; signum <= 1; signum++) {168BigInteger bi = new BigInteger(signum, magZeroLength, 0, 0);169if (bi.compareTo(BigInteger.ZERO) != 0) {170System.err.println("B: Zero length BigInteger != 0 for signum " + signum);171failCount++;172}173}174175byte[] magNonZeroLength = new byte[42];176random.nextBytes(magNonZeroLength);177for (int signum = -1; signum <= 1; signum++) {178BigInteger bi = new BigInteger(signum, magNonZeroLength, 0, 0);179if (bi.compareTo(BigInteger.ZERO) != 0) {180System.err.println("C: Zero length BigInteger != 0 for signum " + signum);181failCount++;182}183}184185// --- tests for accurate creation of non-zero BigIntegers ---186187for (int i = 0; i < SIZE; i++) {188// create reference value via a different code path from those tested189BigInteger reference = new BigInteger(2 + random.nextInt(336), 4, random);190191byte[] refArray = reference.toByteArray();192int refLen = refArray.length;193int factor = random.nextInt(5);194int objLen = refArray.length + factor*random.nextInt(refArray.length) + 1;195int offset = random.nextInt(objLen - refLen);196byte[] objArray = new byte[objLen];197System.arraycopy(refArray, 0, objArray, offset, refLen);198199BigInteger twosComp = new BigInteger(objArray, offset, refLen);200if (twosComp.compareTo(reference) != 0) {201System.err.println("Two's-complement BigInteger not equal for offset " +202offset + " and length " + refLen);203failCount++;204}205206boolean isNegative = random.nextBoolean();207BigInteger signMag = new BigInteger(isNegative ? -1 : 1, objArray, offset, refLen);208if (signMag.compareTo(isNegative ? reference.negate() : reference) != 0) {209System.err.println("Sign-magnitude BigInteger not equal for offset " +210offset + " and length " + refLen);211failCount++;212}213}214215report("Constructor", failCount);216}217218public static void pow(int order) {219int failCount1 = 0;220221for (int i=0; i<SIZE; i++) {222// Test identity x^power == x*x*x ... *x223int power = random.nextInt(6) + 2;224BigInteger x = fetchNumber(order);225BigInteger y = x.pow(power);226BigInteger z = x;227228for (int j=1; j<power; j++)229z = z.multiply(x);230231if (!y.equals(z))232failCount1++;233}234report("pow for " + order + " bits", failCount1);235}236237public static void square(int order) {238int failCount1 = 0;239240for (int i=0; i<SIZE; i++) {241// Test identity x^2 == x*x242BigInteger x = fetchNumber(order);243BigInteger xx = x.multiply(x);244BigInteger x2 = x.pow(2);245246if (!x2.equals(xx))247failCount1++;248}249report("square for " + order + " bits", failCount1);250}251252private static void printErr(String msg) {253System.err.println(msg);254}255256private static int checkResult(BigInteger expected, BigInteger actual,257String failureMessage) {258if (expected.compareTo(actual) != 0) {259printErr(failureMessage + " - expected: " + expected260+ ", actual: " + actual);261return 1;262}263return 0;264}265266private static void squareRootSmall() {267int failCount = 0;268269// A negative value should cause an exception.270BigInteger n = BigInteger.ONE.negate();271BigInteger s;272try {273s = n.sqrt();274// If sqrt() does not throw an exception that is a failure.275failCount++;276printErr("sqrt() of negative number did not throw an exception");277} catch (ArithmeticException expected) {278// A negative value should cause an exception and is not a failure.279}280281// A zero value should return BigInteger.ZERO.282failCount += checkResult(BigInteger.ZERO, BigInteger.ZERO.sqrt(),283"sqrt(0) != BigInteger.ZERO");284285// 1 <= value < 4 should return BigInteger.ONE.286long[] smalls = new long[] {1, 2, 3};287for (long small : smalls) {288failCount += checkResult(BigInteger.ONE,289BigInteger.valueOf(small).sqrt(), "sqrt("+small+") != 1");290}291292report("squareRootSmall", failCount);293}294295public static void squareRoot() {296squareRootSmall();297298ToIntFunction<BigInteger> f = (n) -> {299int failCount = 0;300301// square root of n^2 -> n302BigInteger n2 = n.pow(2);303failCount += checkResult(n, n2.sqrt(), "sqrt() n^2 -> n");304305// square root of n^2 + 1 -> n306BigInteger n2up = n2.add(BigInteger.ONE);307failCount += checkResult(n, n2up.sqrt(), "sqrt() n^2 + 1 -> n");308309// square root of (n + 1)^2 - 1 -> n310BigInteger up =311n.add(BigInteger.ONE).pow(2).subtract(BigInteger.ONE);312failCount += checkResult(n, up.sqrt(), "sqrt() (n + 1)^2 - 1 -> n");313314// sqrt(n)^2 <= n315BigInteger s = n.sqrt();316if (s.multiply(s).compareTo(n) > 0) {317failCount++;318printErr("sqrt(n)^2 > n for n = " + n);319}320321// (sqrt(n) + 1)^2 > n322if (s.add(BigInteger.ONE).pow(2).compareTo(n) <= 0) {323failCount++;324printErr("(sqrt(n) + 1)^2 <= n for n = " + n);325}326327return failCount;328};329330Stream.Builder<BigInteger> sb = Stream.builder();331int maxExponent = Double.MAX_EXPONENT + 1;332for (int i = 1; i <= maxExponent; i++) {333BigInteger p2 = BigInteger.ONE.shiftLeft(i);334sb.add(p2.subtract(BigInteger.ONE));335sb.add(p2);336sb.add(p2.add(BigInteger.ONE));337}338sb.add((new BigDecimal(Double.MAX_VALUE)).toBigInteger());339sb.add((new BigDecimal(Double.MAX_VALUE)).toBigInteger().add(BigInteger.ONE));340report("squareRoot for 2^N and 2^N - 1, 1 <= N <= Double.MAX_EXPONENT",341sb.build().collect(Collectors.summingInt(f)));342343IntStream ints = random.ints(SIZE, 4, Integer.MAX_VALUE);344report("squareRoot for int", ints.mapToObj(x ->345BigInteger.valueOf(x)).collect(Collectors.summingInt(f)));346347LongStream longs = random.longs(SIZE, (long)Integer.MAX_VALUE + 1L,348Long.MAX_VALUE);349report("squareRoot for long", longs.mapToObj(x ->350BigInteger.valueOf(x)).collect(Collectors.summingInt(f)));351352DoubleStream doubles = random.doubles(SIZE,353(double) Long.MAX_VALUE + 1.0, Math.sqrt(Double.MAX_VALUE));354report("squareRoot for double", doubles.mapToObj(x ->355BigDecimal.valueOf(x).toBigInteger()).collect(Collectors.summingInt(f)));356}357358public static void squareRootAndRemainder() {359ToIntFunction<BigInteger> g = (n) -> {360int failCount = 0;361BigInteger n2 = n.pow(2);362363// square root of n^2 -> n364BigInteger[] actual = n2.sqrtAndRemainder();365failCount += checkResult(n, actual[0], "sqrtAndRemainder()[0]");366failCount += checkResult(BigInteger.ZERO, actual[1],367"sqrtAndRemainder()[1]");368369// square root of n^2 + 1 -> n370BigInteger n2up = n2.add(BigInteger.ONE);371actual = n2up.sqrtAndRemainder();372failCount += checkResult(n, actual[0], "sqrtAndRemainder()[0]");373failCount += checkResult(BigInteger.ONE, actual[1],374"sqrtAndRemainder()[1]");375376// square root of (n + 1)^2 - 1 -> n377BigInteger up =378n.add(BigInteger.ONE).pow(2).subtract(BigInteger.ONE);379actual = up.sqrtAndRemainder();380failCount += checkResult(n, actual[0], "sqrtAndRemainder()[0]");381BigInteger r = up.subtract(n2);382failCount += checkResult(r, actual[1], "sqrtAndRemainder()[1]");383384return failCount;385};386387IntStream bits = random.ints(SIZE, 3, Short.MAX_VALUE);388report("sqrtAndRemainder", bits.mapToObj(x ->389BigInteger.valueOf(x)).collect(Collectors.summingInt(g)));390}391392public static void arithmetic(int order) {393int failCount = 0;394395for (int i=0; i<SIZE; i++) {396BigInteger x = fetchNumber(order);397while(x.compareTo(BigInteger.ZERO) != 1)398x = fetchNumber(order);399BigInteger y = fetchNumber(order/2);400while(x.compareTo(y) == -1)401y = fetchNumber(order/2);402if (y.equals(BigInteger.ZERO))403y = y.add(BigInteger.ONE);404405// Test identity ((x/y))*y + x%y - x == 0406// using separate divide() and remainder()407BigInteger baz = x.divide(y);408baz = baz.multiply(y);409baz = baz.add(x.remainder(y));410baz = baz.subtract(x);411if (!baz.equals(BigInteger.ZERO))412failCount++;413}414report("Arithmetic I for " + order + " bits", failCount);415416failCount = 0;417for (int i=0; i<100; i++) {418BigInteger x = fetchNumber(order);419while(x.compareTo(BigInteger.ZERO) != 1)420x = fetchNumber(order);421BigInteger y = fetchNumber(order/2);422while(x.compareTo(y) == -1)423y = fetchNumber(order/2);424if (y.equals(BigInteger.ZERO))425y = y.add(BigInteger.ONE);426427// Test identity ((x/y))*y + x%y - x == 0428// using divideAndRemainder()429BigInteger baz[] = x.divideAndRemainder(y);430baz[0] = baz[0].multiply(y);431baz[0] = baz[0].add(baz[1]);432baz[0] = baz[0].subtract(x);433if (!baz[0].equals(BigInteger.ZERO))434failCount++;435}436report("Arithmetic II for " + order + " bits", failCount);437}438439/**440* Sanity test for Karatsuba and 3-way Toom-Cook multiplication.441* For each of the Karatsuba and 3-way Toom-Cook multiplication thresholds,442* construct two factors each with a mag array one element shorter than the443* threshold, and with the most significant bit set and the rest of the bits444* random. Each of these numbers will therefore be below the threshold but445* if shifted left be above the threshold. Call the numbers 'u' and 'v' and446* define random shifts 'a' and 'b' in the range [1,32]. Then we have the447* identity448* <pre>449* (u << a)*(v << b) = (u*v) << (a + b)450* </pre>451* For Karatsuba multiplication, the right hand expression will be evaluated452* using the standard naive algorithm, and the left hand expression using453* the Karatsuba algorithm. For 3-way Toom-Cook multiplication, the right454* hand expression will be evaluated using Karatsuba multiplication, and the455* left hand expression using 3-way Toom-Cook multiplication.456*/457public static void multiplyLarge() {458int failCount = 0;459460BigInteger base = BigInteger.ONE.shiftLeft(BITS_KARATSUBA - 32 - 1);461for (int i=0; i<SIZE; i++) {462BigInteger x = fetchNumber(BITS_KARATSUBA - 32 - 1);463BigInteger u = base.add(x);464int a = 1 + random.nextInt(31);465BigInteger w = u.shiftLeft(a);466467BigInteger y = fetchNumber(BITS_KARATSUBA - 32 - 1);468BigInteger v = base.add(y);469int b = 1 + random.nextInt(32);470BigInteger z = v.shiftLeft(b);471472BigInteger multiplyResult = u.multiply(v).shiftLeft(a + b);473BigInteger karatsubaMultiplyResult = w.multiply(z);474475if (!multiplyResult.equals(karatsubaMultiplyResult)) {476failCount++;477}478}479480report("multiplyLarge Karatsuba", failCount);481482failCount = 0;483base = base.shiftLeft(BITS_TOOM_COOK - BITS_KARATSUBA);484for (int i=0; i<SIZE; i++) {485BigInteger x = fetchNumber(BITS_TOOM_COOK - 32 - 1);486BigInteger u = base.add(x);487BigInteger u2 = u.shiftLeft(1);488BigInteger y = fetchNumber(BITS_TOOM_COOK - 32 - 1);489BigInteger v = base.add(y);490BigInteger v2 = v.shiftLeft(1);491492BigInteger multiplyResult = u.multiply(v).shiftLeft(2);493BigInteger toomCookMultiplyResult = u2.multiply(v2);494495if (!multiplyResult.equals(toomCookMultiplyResult)) {496failCount++;497}498}499500report("multiplyLarge Toom-Cook", failCount);501}502503/**504* Sanity test for Karatsuba and 3-way Toom-Cook squaring.505* This test is analogous to {@link AbstractMethodError#multiplyLarge}506* with both factors being equal. The squaring methods will not be tested507* unless the <code>bigInteger.multiply(bigInteger)</code> tests whether508* the parameter is the same instance on which the method is being invoked509* and calls <code>square()</code> accordingly.510*/511public static void squareLarge() {512int failCount = 0;513514BigInteger base = BigInteger.ONE.shiftLeft(BITS_KARATSUBA_SQUARE - 32 - 1);515for (int i=0; i<SIZE; i++) {516BigInteger x = fetchNumber(BITS_KARATSUBA_SQUARE - 32 - 1);517BigInteger u = base.add(x);518int a = 1 + random.nextInt(31);519BigInteger w = u.shiftLeft(a);520521BigInteger squareResult = u.multiply(u).shiftLeft(2*a);522BigInteger karatsubaSquareResult = w.multiply(w);523524if (!squareResult.equals(karatsubaSquareResult)) {525failCount++;526}527}528529report("squareLarge Karatsuba", failCount);530531failCount = 0;532base = base.shiftLeft(BITS_TOOM_COOK_SQUARE - BITS_KARATSUBA_SQUARE);533for (int i=0; i<SIZE; i++) {534BigInteger x = fetchNumber(BITS_TOOM_COOK_SQUARE - 32 - 1);535BigInteger u = base.add(x);536int a = 1 + random.nextInt(31);537BigInteger w = u.shiftLeft(a);538539BigInteger squareResult = u.multiply(u).shiftLeft(2*a);540BigInteger toomCookSquareResult = w.multiply(w);541542if (!squareResult.equals(toomCookSquareResult)) {543failCount++;544}545}546547report("squareLarge Toom-Cook", failCount);548}549550/**551* Sanity test for Burnikel-Ziegler division. The Burnikel-Ziegler division552* algorithm is used when each of the dividend and the divisor has at least553* a specified number of ints in its representation. This test is based on554* the observation that if {@code w = u*pow(2,a)} and {@code z = v*pow(2,b)}555* where {@code abs(u) > abs(v)} and {@code a > b && b > 0}, then if556* {@code w/z = q1*z + r1} and {@code u/v = q2*v + r2}, then557* {@code q1 = q2*pow(2,a-b)} and {@code r1 = r2*pow(2,b)}. The test558* ensures that {@code v} is just under the B-Z threshold, that {@code z} is559* over the threshold and {@code w} is much larger than {@code z}. This560* implies that {@code u/v} uses the standard division algorithm and561* {@code w/z} uses the B-Z algorithm. The results of the two algorithms562* are then compared using the observation described in the foregoing and563* if they are not equal a failure is logged.564*/565public static void divideLarge() {566int failCount = 0;567568BigInteger base = BigInteger.ONE.shiftLeft(BITS_BURNIKEL_ZIEGLER + BITS_BURNIKEL_ZIEGLER_OFFSET - 33);569for (int i=0; i<SIZE; i++) {570BigInteger addend = new BigInteger(BITS_BURNIKEL_ZIEGLER + BITS_BURNIKEL_ZIEGLER_OFFSET - 34, random);571BigInteger v = base.add(addend);572573BigInteger u = v.multiply(BigInteger.valueOf(2 + random.nextInt(Short.MAX_VALUE - 1)));574575if(random.nextBoolean()) {576u = u.negate();577}578if(random.nextBoolean()) {579v = v.negate();580}581582int a = BITS_BURNIKEL_ZIEGLER_OFFSET + random.nextInt(16);583int b = 1 + random.nextInt(16);584BigInteger w = u.multiply(BigInteger.ONE.shiftLeft(a));585BigInteger z = v.multiply(BigInteger.ONE.shiftLeft(b));586587BigInteger[] divideResult = u.divideAndRemainder(v);588divideResult[0] = divideResult[0].multiply(BigInteger.ONE.shiftLeft(a - b));589divideResult[1] = divideResult[1].multiply(BigInteger.ONE.shiftLeft(b));590BigInteger[] bzResult = w.divideAndRemainder(z);591592if (divideResult[0].compareTo(bzResult[0]) != 0 ||593divideResult[1].compareTo(bzResult[1]) != 0) {594failCount++;595}596}597598report("divideLarge", failCount);599}600601public static void bitCount() {602int failCount = 0;603604for (int i=0; i<SIZE*10; i++) {605int x = random.nextInt();606BigInteger bigX = BigInteger.valueOf((long)x);607int bit = (x < 0 ? 0 : 1);608int tmp = x, bitCount = 0;609for (int j=0; j<32; j++) {610bitCount += ((tmp & 1) == bit ? 1 : 0);611tmp >>= 1;612}613614if (bigX.bitCount() != bitCount) {615//System.err.println(x+": "+bitCount+", "+bigX.bitCount());616failCount++;617}618}619report("Bit Count", failCount);620}621622public static void bitLength() {623int failCount = 0;624625for (int i=0; i<SIZE*10; i++) {626int x = random.nextInt();627BigInteger bigX = BigInteger.valueOf((long)x);628int signBit = (x < 0 ? 0x80000000 : 0);629int tmp = x, bitLength, j;630for (j=0; j<32 && (tmp & 0x80000000)==signBit; j++)631tmp <<= 1;632bitLength = 32 - j;633634if (bigX.bitLength() != bitLength) {635//System.err.println(x+": "+bitLength+", "+bigX.bitLength());636failCount++;637}638}639640report("BitLength", failCount);641}642643public static void bitOps(int order) {644int failCount1 = 0, failCount2 = 0, failCount3 = 0;645646for (int i=0; i<SIZE*5; i++) {647BigInteger x = fetchNumber(order);648BigInteger y;649650// Test setBit and clearBit (and testBit)651if (x.signum() < 0) {652y = BigInteger.valueOf(-1);653for (int j=0; j<x.bitLength(); j++)654if (!x.testBit(j))655y = y.clearBit(j);656} else {657y = BigInteger.ZERO;658for (int j=0; j<x.bitLength(); j++)659if (x.testBit(j))660y = y.setBit(j);661}662if (!x.equals(y))663failCount1++;664665// Test flipBit (and testBit)666y = BigInteger.valueOf(x.signum()<0 ? -1 : 0);667for (int j=0; j<x.bitLength(); j++)668if (x.signum()<0 ^ x.testBit(j))669y = y.flipBit(j);670if (!x.equals(y))671failCount2++;672}673report("clearBit/testBit for " + order + " bits", failCount1);674report("flipBit/testBit for " + order + " bits", failCount2);675676for (int i=0; i<SIZE*5; i++) {677BigInteger x = fetchNumber(order);678679// Test getLowestSetBit()680int k = x.getLowestSetBit();681if (x.signum() == 0) {682if (k != -1)683failCount3++;684} else {685BigInteger z = x.and(x.negate());686int j;687for (j=0; j<z.bitLength() && !z.testBit(j); j++)688;689if (k != j)690failCount3++;691}692}693report("getLowestSetBit for " + order + " bits", failCount3);694}695696public static void bitwise(int order) {697698// Test identity x^y == x|y &~ x&y699int failCount = 0;700for (int i=0; i<SIZE; i++) {701BigInteger x = fetchNumber(order);702BigInteger y = fetchNumber(order);703BigInteger z = x.xor(y);704BigInteger w = x.or(y).andNot(x.and(y));705if (!z.equals(w))706failCount++;707}708report("Logic (^ | & ~) for " + order + " bits", failCount);709710// Test identity x &~ y == ~(~x | y)711failCount = 0;712for (int i=0; i<SIZE; i++) {713BigInteger x = fetchNumber(order);714BigInteger y = fetchNumber(order);715BigInteger z = x.andNot(y);716BigInteger w = x.not().or(y).not();717if (!z.equals(w))718failCount++;719}720report("Logic (&~ | ~) for " + order + " bits", failCount);721}722723public static void shift(int order) {724int failCount1 = 0;725int failCount2 = 0;726int failCount3 = 0;727728for (int i=0; i<100; i++) {729BigInteger x = fetchNumber(order);730int n = Math.abs(random.nextInt()%200);731732if (!x.shiftLeft(n).equals733(x.multiply(BigInteger.valueOf(2L).pow(n))))734failCount1++;735736BigInteger y[] =x.divideAndRemainder(BigInteger.valueOf(2L).pow(n));737BigInteger z = (x.signum()<0 && y[1].signum()!=0738? y[0].subtract(BigInteger.ONE)739: y[0]);740741BigInteger b = x.shiftRight(n);742743if (!b.equals(z)) {744System.err.println("Input is "+x.toString(2));745System.err.println("shift is "+n);746747System.err.println("Divided "+z.toString(2));748System.err.println("Shifted is "+b.toString(2));749if (b.toString().equals(z.toString()))750System.err.println("Houston, we have a problem.");751failCount2++;752}753754if (!x.shiftLeft(n).shiftRight(n).equals(x))755failCount3++;756}757report("baz shiftLeft for " + order + " bits", failCount1);758report("baz shiftRight for " + order + " bits", failCount2);759report("baz shiftLeft/Right for " + order + " bits", failCount3);760}761762public static void divideAndRemainder(int order) {763int failCount1 = 0;764765for (int i=0; i<SIZE; i++) {766BigInteger x = fetchNumber(order).abs();767while(x.compareTo(BigInteger.valueOf(3L)) != 1)768x = fetchNumber(order).abs();769BigInteger z = x.divide(BigInteger.valueOf(2L));770BigInteger y[] = x.divideAndRemainder(x);771if (!y[0].equals(BigInteger.ONE)) {772failCount1++;773System.err.println("fail1 x :"+x);774System.err.println(" y :"+y);775}776else if (!y[1].equals(BigInteger.ZERO)) {777failCount1++;778System.err.println("fail2 x :"+x);779System.err.println(" y :"+y);780}781782y = x.divideAndRemainder(z);783if (!y[0].equals(BigInteger.valueOf(2))) {784failCount1++;785System.err.println("fail3 x :"+x);786System.err.println(" y :"+y);787}788}789report("divideAndRemainder for " + order + " bits", failCount1);790}791792public static void stringConv() {793int failCount = 0;794795// Generic string conversion.796for (int i=0; i<100; i++) {797byte xBytes[] = new byte[Math.abs(random.nextInt())%200+1];798random.nextBytes(xBytes);799BigInteger x = new BigInteger(xBytes);800801for (int radix=Character.MIN_RADIX; radix < Character.MAX_RADIX; radix++) {802String result = x.toString(radix);803BigInteger test = new BigInteger(result, radix);804if (!test.equals(x)) {805failCount++;806System.err.println("BigInteger toString: "+x);807System.err.println("Test: "+test);808System.err.println(radix);809}810}811}812813// String conversion straddling the Schoenhage algorithm crossover814// threshold, and at twice and four times the threshold.815for (int k = 0; k <= 2; k++) {816int factor = 1 << k;817int upper = factor * BITS_SCHOENHAGE_BASE + 33;818int lower = upper - 35;819820for (int bits = upper; bits >= lower; bits--) {821for (int i = 0; i < 50; i++) {822BigInteger x = BigInteger.ONE.shiftLeft(bits - 1).or(new BigInteger(bits - 2, random));823824for (int radix = Character.MIN_RADIX; radix < Character.MAX_RADIX; radix++) {825String result = x.toString(radix);826BigInteger test = new BigInteger(result, radix);827if (!test.equals(x)) {828failCount++;829System.err.println("BigInteger toString: " + x);830System.err.println("Test: " + test);831System.err.println(radix);832}833}834}835}836}837838// Check value with many trailing zeros.839String val = "123456789" + "0".repeat(200);840BigInteger b = new BigInteger(val);841String s = b.toString();842if (!val.equals(s)) {843System.err.format("Expected length %d but got %d%n",844val.length(), s.length());845failCount++;846}847848report("String Conversion", failCount);849}850851public static void byteArrayConv(int order) {852int failCount = 0;853854for (int i=0; i<SIZE; i++) {855BigInteger x = fetchNumber(order);856while (x.equals(BigInteger.ZERO))857x = fetchNumber(order);858BigInteger y = new BigInteger(x.toByteArray());859if (!x.equals(y)) {860failCount++;861System.err.println("orig is "+x);862System.err.println("new is "+y);863}864}865report("Array Conversion for " + order + " bits", failCount);866}867868public static void modInv(int order) {869int failCount = 0, successCount = 0, nonInvCount = 0;870871for (int i=0; i<SIZE; i++) {872BigInteger x = fetchNumber(order);873while(x.equals(BigInteger.ZERO))874x = fetchNumber(order);875BigInteger m = fetchNumber(order).abs();876while(m.compareTo(BigInteger.ONE) != 1)877m = fetchNumber(order).abs();878879try {880BigInteger inv = x.modInverse(m);881BigInteger prod = inv.multiply(x).remainder(m);882883if (prod.signum() == -1)884prod = prod.add(m);885886if (prod.equals(BigInteger.ONE))887successCount++;888else889failCount++;890} catch(ArithmeticException e) {891nonInvCount++;892}893}894report("Modular Inverse for " + order + " bits", failCount);895}896897public static void modExp(int order1, int order2) {898int failCount = 0;899900for (int i=0; i<SIZE/10; i++) {901BigInteger m = fetchNumber(order1).abs();902while(m.compareTo(BigInteger.ONE) != 1)903m = fetchNumber(order1).abs();904BigInteger base = fetchNumber(order2);905BigInteger exp = fetchNumber(8).abs();906907BigInteger z = base.modPow(exp, m);908BigInteger w = base.pow(exp.intValue()).mod(m);909if (!z.equals(w)) {910System.err.println("z is "+z);911System.err.println("w is "+w);912System.err.println("mod is "+m);913System.err.println("base is "+base);914System.err.println("exp is "+exp);915failCount++;916}917}918report("Exponentiation I for " + order1 + " and " +919order2 + " bits", failCount);920}921922// This test is based on Fermat's theorem923// which is not ideal because base must not be multiple of modulus924// and modulus must be a prime or pseudoprime (Carmichael number)925public static void modExp2(int order) {926int failCount = 0;927928for (int i=0; i<10; i++) {929BigInteger m = new BigInteger(100, 5, random);930while(m.compareTo(BigInteger.ONE) != 1)931m = new BigInteger(100, 5, random);932BigInteger exp = m.subtract(BigInteger.ONE);933BigInteger base = fetchNumber(order).abs();934while(base.compareTo(m) != -1)935base = fetchNumber(order).abs();936while(base.equals(BigInteger.ZERO))937base = fetchNumber(order).abs();938939BigInteger one = base.modPow(exp, m);940if (!one.equals(BigInteger.ONE)) {941System.err.println("m is "+m);942System.err.println("base is "+base);943System.err.println("exp is "+exp);944failCount++;945}946}947report("Exponentiation II for " + order + " bits", failCount);948}949950private static final int[] mersenne_powers = {951521, 607, 1279, 2203, 2281, 3217, 4253, 4423, 9689, 9941, 11213, 19937,95221701, 23209, 44497, 86243, 110503, 132049, 216091, 756839, 859433,9531257787, 1398269, 2976221, 3021377, 6972593, 13466917 };954955private static final long[] carmichaels = {956561,1105,1729,2465,2821,6601,8911,10585,15841,29341,41041,46657,52633,95762745,63973,75361,101101,115921,126217,162401,172081,188461,252601,958278545,294409,314821,334153,340561,399001,410041,449065,488881,512461,959225593397919L };960961// Note: testing the larger ones takes too long.962private static final int NUM_MERSENNES_TO_TEST = 7;963// Note: this constant used for computed Carmichaels, not the array above964private static final int NUM_CARMICHAELS_TO_TEST = 5;965966private static final String[] customer_primes = {967"120000000000000000000000000000000019",968"633825300114114700748351603131",969"1461501637330902918203684832716283019651637554291",970"779626057591079617852292862756047675913380626199",971"857591696176672809403750477631580323575362410491",972"910409242326391377348778281801166102059139832131",973"929857869954035706722619989283358182285540127919",974"961301750640481375785983980066592002055764391999",975"1267617700951005189537696547196156120148404630231",976"1326015641149969955786344600146607663033642528339" };977978private static final BigInteger ZERO = BigInteger.ZERO;979private static final BigInteger ONE = BigInteger.ONE;980private static final BigInteger TWO = new BigInteger("2");981private static final BigInteger SIX = new BigInteger("6");982private static final BigInteger TWELVE = new BigInteger("12");983private static final BigInteger EIGHTEEN = new BigInteger("18");984985public static void prime() {986BigInteger p1, p2, c1;987int failCount = 0;988989// Test consistency990for(int i=0; i<10; i++) {991p1 = BigInteger.probablePrime(100, random);992if (!p1.isProbablePrime(100)) {993System.err.println("Consistency "+p1.toString(16));994failCount++;995}996}997998// Test some known Mersenne primes (2^n)-1999// The array holds the exponents, not the numbers being tested1000for (int i=0; i<NUM_MERSENNES_TO_TEST; i++) {1001p1 = new BigInteger("2");1002p1 = p1.pow(mersenne_powers[i]);1003p1 = p1.subtract(BigInteger.ONE);1004if (!p1.isProbablePrime(100)) {1005System.err.println("Mersenne prime "+i+ " failed.");1006failCount++;1007}1008}10091010// Test some primes reported by customers as failing in the past1011for (int i=0; i<customer_primes.length; i++) {1012p1 = new BigInteger(customer_primes[i]);1013if (!p1.isProbablePrime(100)) {1014System.err.println("Customer prime "+i+ " failed.");1015failCount++;1016}1017}10181019// Test some known Carmichael numbers.1020for (int i=0; i<carmichaels.length; i++) {1021c1 = BigInteger.valueOf(carmichaels[i]);1022if(c1.isProbablePrime(100)) {1023System.err.println("Carmichael "+i+ " reported as prime.");1024failCount++;1025}1026}10271028// Test some computed Carmichael numbers.1029// Numbers of the form (6k+1)(12k+1)(18k+1) are Carmichael numbers if1030// each of the factors is prime1031int found = 0;1032BigInteger f1 = new BigInteger(40, 100, random);1033while (found < NUM_CARMICHAELS_TO_TEST) {1034BigInteger k = null;1035BigInteger f2, f3;1036f1 = f1.nextProbablePrime();1037BigInteger[] result = f1.subtract(ONE).divideAndRemainder(SIX);1038if (result[1].equals(ZERO)) {1039k = result[0];1040f2 = k.multiply(TWELVE).add(ONE);1041if (f2.isProbablePrime(100)) {1042f3 = k.multiply(EIGHTEEN).add(ONE);1043if (f3.isProbablePrime(100)) {1044c1 = f1.multiply(f2).multiply(f3);1045if (c1.isProbablePrime(100)) {1046System.err.println("Computed Carmichael "1047+c1.toString(16));1048failCount++;1049}1050found++;1051}1052}1053}1054f1 = f1.add(TWO);1055}10561057// Test some composites that are products of 2 primes1058for (int i=0; i<50; i++) {1059p1 = BigInteger.probablePrime(100, random);1060p2 = BigInteger.probablePrime(100, random);1061c1 = p1.multiply(p2);1062if (c1.isProbablePrime(100)) {1063System.err.println("Composite failed "+c1.toString(16));1064failCount++;1065}1066}10671068for (int i=0; i<4; i++) {1069p1 = BigInteger.probablePrime(600, random);1070p2 = BigInteger.probablePrime(600, random);1071c1 = p1.multiply(p2);1072if (c1.isProbablePrime(100)) {1073System.err.println("Composite failed "+c1.toString(16));1074failCount++;1075}1076}10771078report("Prime", failCount);1079}10801081private static final long[] primesTo100 = {10822,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,971083};10841085private static final long[] aPrimeSequence = {10861999999003L, 1999999013L, 1999999049L, 1999999061L, 1999999081L,10871999999087L, 1999999093L, 1999999097L, 1999999117L, 1999999121L,10881999999151L, 1999999171L, 1999999207L, 1999999219L, 1999999271L,10891999999321L, 1999999373L, 1999999423L, 1999999439L, 1999999499L,10901999999553L, 1999999559L, 1999999571L, 1999999609L, 1999999613L,10911999999621L, 1999999643L, 1999999649L, 1999999657L, 1999999747L,10921999999763L, 1999999777L, 1999999811L, 1999999817L, 1999999829L,10931999999853L, 1999999861L, 1999999871L, 19999998731094};10951096public static void nextProbablePrime() throws Exception {1097int failCount = 0;1098BigInteger p1, p2, p3;1099p1 = p2 = p3 = ZERO;11001101// First test nextProbablePrime on the low range starting at zero1102for (int i=0; i<primesTo100.length; i++) {1103p1 = p1.nextProbablePrime();1104if (p1.longValue() != primesTo100[i]) {1105System.err.println("low range primes failed");1106System.err.println("p1 is "+p1);1107System.err.println("expected "+primesTo100[i]);1108failCount++;1109}1110}11111112// Test nextProbablePrime on a relatively small, known prime sequence1113p1 = BigInteger.valueOf(aPrimeSequence[0]);1114for (int i=1; i<aPrimeSequence.length; i++) {1115p1 = p1.nextProbablePrime();1116if (p1.longValue() != aPrimeSequence[i]) {1117System.err.println("prime sequence failed");1118failCount++;1119}1120}11211122// Next, pick some large primes, use nextProbablePrime to find the1123// next one, and make sure there are no primes in between1124for (int i=0; i<100; i+=10) {1125p1 = BigInteger.probablePrime(50 + i, random);1126p2 = p1.add(ONE);1127p3 = p1.nextProbablePrime();1128while(p2.compareTo(p3) < 0) {1129if (p2.isProbablePrime(100)){1130System.err.println("nextProbablePrime failed");1131System.err.println("along range "+p1.toString(16));1132System.err.println("to "+p3.toString(16));1133failCount++;1134break;1135}1136p2 = p2.add(ONE);1137}1138}11391140report("nextProbablePrime", failCount);1141}11421143public static void serialize() throws Exception {1144int failCount = 0;11451146String bitPatterns[] = {1147"ffffffff00000000ffffffff00000000ffffffff00000000",1148"ffffffffffffffffffffffff000000000000000000000000",1149"ffffffff0000000000000000000000000000000000000000",1150"10000000ffffffffffffffffffffffffffffffffffffffff",1151"100000000000000000000000000000000000000000000000",1152"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",1153"-ffffffff00000000ffffffff00000000ffffffff00000000",1154"-ffffffffffffffffffffffff000000000000000000000000",1155"-ffffffff0000000000000000000000000000000000000000",1156"-10000000ffffffffffffffffffffffffffffffffffffffff",1157"-100000000000000000000000000000000000000000000000",1158"-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"1159};11601161for(int i = 0; i < bitPatterns.length; i++) {1162BigInteger b1 = new BigInteger(bitPatterns[i], 16);1163BigInteger b2 = null;11641165File f = new File("serialtest");11661167try (FileOutputStream fos = new FileOutputStream(f)) {1168try (ObjectOutputStream oos = new ObjectOutputStream(fos)) {1169oos.writeObject(b1);1170oos.flush();1171}11721173try (FileInputStream fis = new FileInputStream(f);1174ObjectInputStream ois = new ObjectInputStream(fis))1175{1176b2 = (BigInteger)ois.readObject();1177}11781179if (!b1.equals(b2) ||1180!b1.equals(b1.or(b2))) {1181failCount++;1182System.err.println("Serialized failed for hex " +1183b1.toString(16));1184}1185}1186f.delete();1187}11881189for(int i=0; i<10; i++) {1190BigInteger b1 = fetchNumber(random.nextInt(100));1191BigInteger b2 = null;1192File f = new File("serialtest");1193try (FileOutputStream fos = new FileOutputStream(f)) {1194try (ObjectOutputStream oos = new ObjectOutputStream(fos)) {1195oos.writeObject(b1);1196oos.flush();1197}11981199try (FileInputStream fis = new FileInputStream(f);1200ObjectInputStream ois = new ObjectInputStream(fis))1201{1202b2 = (BigInteger)ois.readObject();1203}1204}12051206if (!b1.equals(b2) ||1207!b1.equals(b1.or(b2)))1208failCount++;1209f.delete();1210}12111212report("Serialize", failCount);1213}12141215/**1216* Main to interpret arguments and run several tests.1217*1218* Up to three arguments may be given to specify the SIZE of BigIntegers1219* used for call parameters 1, 2, and 3. The SIZE is interpreted as1220* the maximum number of decimal digits that the parameters will have.1221*1222*/1223public static void main(String[] args) throws Exception {1224// Some variables for sizing test numbers in bits1225int order1 = ORDER_MEDIUM;1226int order2 = ORDER_SMALL;1227int order3 = ORDER_KARATSUBA;1228int order4 = ORDER_TOOM_COOK;12291230if (args.length >0)1231order1 = (int)((Integer.parseInt(args[0]))* 3.333);1232if (args.length >1)1233order2 = (int)((Integer.parseInt(args[1]))* 3.333);1234if (args.length >2)1235order3 = (int)((Integer.parseInt(args[2]))* 3.333);1236if (args.length >3)1237order4 = (int)((Integer.parseInt(args[3]))* 3.333);12381239constructor();12401241prime();1242nextProbablePrime();12431244arithmetic(order1); // small numbers1245arithmetic(order3); // Karatsuba range1246arithmetic(order4); // Toom-Cook / Burnikel-Ziegler range12471248divideAndRemainder(order1); // small numbers1249divideAndRemainder(order3); // Karatsuba range1250divideAndRemainder(order4); // Toom-Cook / Burnikel-Ziegler range12511252pow(order1);1253pow(order3);1254pow(order4);12551256square(ORDER_MEDIUM);1257square(ORDER_KARATSUBA_SQUARE);1258square(ORDER_TOOM_COOK_SQUARE);12591260squareRoot();1261squareRootAndRemainder();12621263bitCount();1264bitLength();1265bitOps(order1);1266bitwise(order1);12671268shift(order1);12691270byteArrayConv(order1);12711272modInv(order1); // small numbers1273modInv(order3); // Karatsuba range1274modInv(order4); // Toom-Cook / Burnikel-Ziegler range12751276modExp(order1, order2);1277modExp2(order1);12781279stringConv();1280serialize();12811282multiplyLarge();1283squareLarge();1284divideLarge();12851286if (failure)1287throw new RuntimeException("Failure in BigIntegerTest.");1288}12891290/*1291* Get a random or boundary-case number. This is designed to provide1292* a lot of numbers that will find failure points, such as max sized1293* numbers, empty BigIntegers, etc.1294*1295* If order is less than 2, order is changed to 2.1296*/1297private static BigInteger fetchNumber(int order) {1298boolean negative = random.nextBoolean();1299int numType = random.nextInt(7);1300BigInteger result = null;1301if (order < 2) order = 2;13021303switch (numType) {1304case 0: // Empty1305result = BigInteger.ZERO;1306break;13071308case 1: // One1309result = BigInteger.ONE;1310break;13111312case 2: // All bits set in number1313int numBytes = (order+7)/8;1314byte[] fullBits = new byte[numBytes];1315for(int i=0; i<numBytes; i++)1316fullBits[i] = (byte)0xff;1317int excessBits = 8*numBytes - order;1318fullBits[0] &= (1 << (8-excessBits)) - 1;1319result = new BigInteger(1, fullBits);1320break;13211322case 3: // One bit in number1323result = BigInteger.ONE.shiftLeft(random.nextInt(order));1324break;13251326case 4: // Random bit density1327byte[] val = new byte[(order+7)/8];1328int iterations = random.nextInt(order);1329for (int i=0; i<iterations; i++) {1330int bitIdx = random.nextInt(order);1331val[bitIdx/8] |= 1 << (bitIdx%8);1332}1333result = new BigInteger(1, val);1334break;1335case 5: // Runs of consecutive ones and zeros1336result = ZERO;1337int remaining = order;1338int bit = random.nextInt(2);1339while (remaining > 0) {1340int runLength = Math.min(remaining, random.nextInt(order));1341result = result.shiftLeft(runLength);1342if (bit > 0)1343result = result.add(ONE.shiftLeft(runLength).subtract(ONE));1344remaining -= runLength;1345bit = 1 - bit;1346}1347break;13481349default: // random bits1350result = new BigInteger(order, random);1351}13521353if (negative)1354result = result.negate();13551356return result;1357}13581359static void report(String testName, int failCount) {1360System.err.println(testName+": " +1361(failCount==0 ? "Passed":"Failed("+failCount+")"));1362if (failCount > 0)1363failure = true;1364}1365}136613671368