/* * Copyright (c) 1998, 2017, 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 * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /* * @test * @library /test/lib * @build jdk.test.lib.RandomFactory * @run main BigIntegerTest * @bug 4181191 4161971 4227146 4194389 4823171 4624738 4812225 4837946 4026465 8074460 8078672 8032027 * @summary tests methods in BigInteger (use -Dseed=X to set PRNG seed) * @run main/timeout=400 BigIntegerTest * @author madbot * @key randomness */ package test.java.math.BigInteger; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Random; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.DoubleStream; import java.util.stream.IntStream; import java.util.stream.LongStream; import java.util.stream.Stream; import org.testng.Assert; import org.testng.annotations.Test; /** * This is a simple test class created to ensure that the results * generated by BigInteger adhere to certain identities. Passing * this test is a strong assurance that the BigInteger operations * are working correctly. * * Four arguments may be specified which give the number of * decimal digits you desire in the four batches of test numbers. * * The tests are performed on arrays of random numbers which are * generated by a Random class as well as special cases which * throw in boundary numbers such as 0, 1, maximum sized, etc. * */ // Android-changed: Replace error counting with asserts. public class BigIntegerTest { // // Bit large number thresholds based on the int thresholds // defined in BigInteger itself: // // KARATSUBA_THRESHOLD = 80 ints = 2560 bits // TOOM_COOK_THRESHOLD = 240 ints = 7680 bits // KARATSUBA_SQUARE_THRESHOLD = 128 ints = 4096 bits // TOOM_COOK_SQUARE_THRESHOLD = 216 ints = 6912 bits // // SCHOENHAGE_BASE_CONVERSION_THRESHOLD = 20 ints = 640 bits // // BURNIKEL_ZIEGLER_THRESHOLD = 80 ints = 2560 bits // static final int BITS_KARATSUBA = 2560; static final int BITS_TOOM_COOK = 7680; static final int BITS_KARATSUBA_SQUARE = 4096; static final int BITS_TOOM_COOK_SQUARE = 6912; static final int BITS_SCHOENHAGE_BASE = 640; static final int BITS_BURNIKEL_ZIEGLER = 2560; static final int BITS_BURNIKEL_ZIEGLER_OFFSET = 1280; static final int ORDER_SMALL = 60; static final int ORDER_MEDIUM = 100; // #bits for testing Karatsuba static final int ORDER_KARATSUBA = 2760; // #bits for testing Toom-Cook and Burnikel-Ziegler static final int ORDER_TOOM_COOK = 8000; // #bits for testing Karatsuba squaring static final int ORDER_KARATSUBA_SQUARE = 4200; // #bits for testing Toom-Cook squaring static final int ORDER_TOOM_COOK_SQUARE = 7000; static final int SIZE = 1000; // numbers per batch private static Random random = new Random(); static boolean failure = false; private static void constructor() { // --- guard condition tests for array indexing --- int arrayLength = 23; int halfLength = arrayLength/2; byte[] array = new byte[arrayLength]; random.nextBytes(array); int[][] offLen = new int[][] { // offset, length, num exceptions {-1, arrayLength, 1}, // negative offset {0, arrayLength, 0}, // OK {1, arrayLength, 1}, // length overflow {arrayLength - 1, 1, 0}, // OK {arrayLength, 1, 1}, // offset overflow {0, -1, 1}, // negative length {halfLength, arrayLength - halfLength + 1, 1} // length overflow }; // two's complement for (int[] ol : offLen) { try { BigInteger bi = new BigInteger(array, ol[0], ol[1]); if (ol[2] == 1) { Assert.fail("IndexOutOfBoundsException did not occur for " + " two's complement constructor with parameters offset " + ol[0] + " and length " + ol[1]); } } catch (IndexOutOfBoundsException e) { if (ol[2] == 0) { Assert.fail("Unexpected IndexOutOfBoundsException did occur for " + " two's complement constructor with parameters offset " + ol[0] + " and length " + ol[1]); } } } // sign-magnitude for (int[] ol : offLen) { try { BigInteger bi = new BigInteger(1, array, ol[0], ol[1]); if (ol[2] == 1) { Assert.fail("IndexOutOfBoundsException did not occur for " + " sign-magnitude constructor with parameters offset " + ol[0] + " and length " + ol[1]); } } catch (IndexOutOfBoundsException e) { if (ol[2] == 0) { Assert.fail("Unexpected IndexOutOfBoundsException did occur for " + " two's complement constructor with parameters offset " + ol[0] + " and length " + ol[1]); } } } // --- tests for creation of zero-valued BigIntegers --- byte[] magZeroLength = new byte[0]; for (int signum = -1; signum <= 1; signum++) { BigInteger bi = new BigInteger(signum, magZeroLength); Assert.assertEquals(bi.compareTo(BigInteger.ZERO), 0, "A: Zero length BigInteger != 0 for signum " + signum); } for (int signum = -1; signum <= 1; signum++) { BigInteger bi = new BigInteger(signum, magZeroLength, 0, 0); Assert.assertEquals(bi.compareTo(BigInteger.ZERO), 0, "B: Zero length BigInteger != 0 for signum " + signum); } byte[] magNonZeroLength = new byte[42]; random.nextBytes(magNonZeroLength); for (int signum = -1; signum <= 1; signum++) { BigInteger bi = new BigInteger(signum, magNonZeroLength, 0, 0); Assert.assertEquals(bi.compareTo(BigInteger.ZERO), 0, "C: Zero length BigInteger != 0 for signum " + signum); } // --- tests for accurate creation of non-zero BigIntegers --- for (int i = 0; i < SIZE; i++) { // create reference value via a different code path from those tested BigInteger reference = new BigInteger(2 + random.nextInt(336), 4, random); byte[] refArray = reference.toByteArray(); int refLen = refArray.length; int factor = random.nextInt(5); int objLen = refArray.length + factor*random.nextInt(refArray.length) + 1; int offset = random.nextInt(objLen - refLen); byte[] objArray = new byte[objLen]; System.arraycopy(refArray, 0, objArray, offset, refLen); BigInteger twosComp = new BigInteger(objArray, offset, refLen); Assert.assertEquals(twosComp.compareTo(reference), 0, "Two's-complement BigInteger not equal for offset " + offset + " and length " + refLen); boolean isNegative = random.nextBoolean(); BigInteger signMag = new BigInteger(isNegative ? -1 : 1, objArray, offset, refLen); Assert.assertEquals(signMag.compareTo(isNegative ? reference.negate() : reference), 0, "Sign-magnitude BigInteger not equal for offset " + offset + " and length " + refLen); } } private static void pow(int order) { for (int i=0; i f = (n) -> { // square root of n^2 -> n BigInteger n2 = n.pow(2); checkResult(n, n2.sqrt(), "sqrt() n^2 -> n"); // square root of n^2 + 1 -> n BigInteger n2up = n2.add(BigInteger.ONE); checkResult(n, n2up.sqrt(), "sqrt() n^2 + 1 -> n"); // square root of (n + 1)^2 - 1 -> n BigInteger up = n.add(BigInteger.ONE).pow(2).subtract(BigInteger.ONE); checkResult(n, up.sqrt(), "sqrt() (n + 1)^2 - 1 -> n"); // sqrt(n)^2 <= n BigInteger s = n.sqrt(); Assert.assertFalse(s.multiply(s).compareTo(n) > 0, "sqrt(n)^2 > n for n = " + n); // (sqrt(n) + 1)^2 > n Assert.assertFalse(s.add(BigInteger.ONE).pow(2).compareTo(n) <= 0, "(sqrt(n) + 1)^2 <= n for n = " + n); return null; }; Stream.Builder sb = Stream.builder(); int maxExponent = Double.MAX_EXPONENT + 1; for (int i = 1; i <= maxExponent; i++) { BigInteger p2 = BigInteger.ONE.shiftLeft(i); sb.add(p2.subtract(BigInteger.ONE)); sb.add(p2); sb.add(p2.add(BigInteger.ONE)); } sb.add((new BigDecimal(Double.MAX_VALUE)).toBigInteger()); sb.add((new BigDecimal(Double.MAX_VALUE)).toBigInteger().add(BigInteger.ONE)); // "squareRoot for 2^N and 2^N - 1, 1 <= N <= Double.MAX_EXPONENT" sb.build().map(f).collect(Collectors.toList()); IntStream ints = random.ints(SIZE, 4, Integer.MAX_VALUE); ints.mapToObj(BigInteger::valueOf).map(f).collect(Collectors.toList()); LongStream longs = random.longs(SIZE, (long)Integer.MAX_VALUE + 1L, Long.MAX_VALUE); longs.mapToObj(BigInteger::valueOf).map(f).collect(Collectors.toList()); DoubleStream doubles = random.doubles(SIZE, (double) Long.MAX_VALUE + 1.0, Math.sqrt(Double.MAX_VALUE)); doubles.mapToObj(x -> BigDecimal.valueOf(x).toBigInteger()).map(f).collect(Collectors.toList()); } private static void squareRootAndRemainder() { Function g = (n) -> { BigInteger n2 = n.pow(2); // square root of n^2 -> n BigInteger[] actual = n2.sqrtAndRemainder(); checkResult(n, actual[0], "sqrtAndRemainder()[0]"); checkResult(BigInteger.ZERO, actual[1], "sqrtAndRemainder()[1]"); // square root of n^2 + 1 -> n BigInteger n2up = n2.add(BigInteger.ONE); actual = n2up.sqrtAndRemainder(); checkResult(n, actual[0], "sqrtAndRemainder()[0]"); checkResult(BigInteger.ONE, actual[1], "sqrtAndRemainder()[1]"); // square root of (n + 1)^2 - 1 -> n BigInteger up = n.add(BigInteger.ONE).pow(2).subtract(BigInteger.ONE); actual = up.sqrtAndRemainder(); checkResult(n, actual[0], "sqrtAndRemainder()[0]"); BigInteger r = up.subtract(n2); checkResult(r, actual[1], "sqrtAndRemainder()[1]"); return null; }; IntStream bits = random.ints(SIZE, 3, Short.MAX_VALUE); bits.mapToObj(BigInteger::valueOf).map(g).collect(Collectors.toList()); } private static void arithmetic(int order) { for (int i=0; i * (u << a)*(v << b) = (u*v) << (a + b) * * 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. */ private static void multiplyLarge() { BigInteger base = BigInteger.ONE.shiftLeft(BITS_KARATSUBA - 32 - 1); for (int i=0; ibigInteger.multiply(bigInteger) tests whether * the parameter is the same instance on which the method is being invoked * and calls square() accordingly. */ private static void squareLarge() { BigInteger base = BigInteger.ONE.shiftLeft(BITS_KARATSUBA_SQUARE - 32 - 1); for (int i=0; i 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, that {@code z} is * over the threshold and {@code w} is much larger than {@code z}. 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. */ private static void divideLarge() { BigInteger base = BigInteger.ONE.shiftLeft(BITS_BURNIKEL_ZIEGLER + BITS_BURNIKEL_ZIEGLER_OFFSET - 33); for (int i=0; i>= 1; } Assert.assertEquals (bigX.bitCount(), bitCount); } } private static void bitLength() { for (int i=0; i= lower; bits--) { for (int i = 0; i < samples; i++) { BigInteger x = BigInteger.ONE.shiftLeft(bits - 1).or(new BigInteger(bits - 2, random)); for (int radix = Character.MIN_RADIX; radix < Character.MAX_RADIX; radix++) { String result = x.toString(radix); BigInteger test = new BigInteger(result, radix); Assert.assertEquals(test, x, "BigInteger toString: "+x+" Test: "+test+" radix: " + radix); } } } } private static void byteArrayConv(int order) { for (int i=0; i 0) { int runLength = Math.min(remaining, random.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, random); } if (negative) result = result.negate(); return result; } }