alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (BigIntegerTest.java)

This example Java source code file (BigIntegerTest.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

biginteger, burnikel\-ziegler, exception, file, fileinputstream, fileoutputstream, karatsuba, math, objectinputstream, objectoutputstream, one, random, string, toom-cook, util, zero

The BigIntegerTest.java Java example source code

/*
 * 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
 * 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
 * @bug 4181191 4161971 4227146 4194389 4823171 4624738 4812225 4837946
 * @summary tests methods in BigInteger
 * @run main/timeout=400 BigIntegerTest
 * @author madbot
 */

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.util.Random;

/**
 * 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.
 *
 */
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 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

    static Random rnd = new Random();
    static boolean failure = false;

    public static void pow(int order) {
        int failCount1 = 0;

        for (int i=0; i<SIZE; i++) {
            // 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;

            for (int j=1; j<power; j++)
                z = z.multiply(x);

            if (!y.equals(z))
                failCount1++;
        }
        report("pow for " + order + " bits", failCount1);
    }

    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(order);
            while(x.compareTo(BigInteger.ZERO) != 1)
                x = fetchNumber(order);
            BigInteger y = fetchNumber(order/2);
            while(x.compareTo(y) == -1)
                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));
            baz = baz.subtract(x);
            if (!baz.equals(BigInteger.ZERO))
                failCount++;
        }
        report("Arithmetic I for " + order + " bits", failCount);

        failCount = 0;
        for (int i=0; i<100; i++) {
            BigInteger x = fetchNumber(order);
            while(x.compareTo(BigInteger.ZERO) != 1)
                x = fetchNumber(order);
            BigInteger y = fetchNumber(order/2);
            while(x.compareTo(y) == -1)
                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]);
            baz[0] = baz[0].subtract(x);
            if (!baz[0].equals(BigInteger.ZERO))
                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) tests whether
     * the parameter is the same instance on which the method is being invoked
     * and calls <code>square() 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);
    }

    /**
     * Sanity test for Burnikel-Ziegler division.  The Burnikel-Ziegler division
     * algorithm is used when each of the dividend and the divisor has at least
     * a specified number of ints in its representation.  This test is based on
     * the observation that if {@code w = u*pow(2,a)} and {@code z = v*pow(2,b)}
     * where {@code abs(u) > abs(v)} and {@code a > b && b > 0}, then if
     * {@code w/z = q1*z + r1} and {@code u/v = q2*v + r2}, then
     * {@code q1 = q2*pow(2,a-b)} and {@code r1 = r2*pow(2,b)}.  The test
     * ensures that {@code v} is just under the B-Z threshold and that {@code w}
     * and {@code z} are both over the threshold.  This implies that {@code u/v}
     * uses the standard division algorithm and {@code w/z} uses the B-Z
     * algorithm.  The results of the two algorithms are then compared using the
     * observation described in the foregoing and if they are not equal a
     * failure is logged.
     */
    public static void divideLarge() {
        int failCount = 0;

        BigInteger base = BigInteger.ONE.shiftLeft(BITS_BURNIKEL_ZIEGLER - 33);
        for (int i=0; i<SIZE; i++) {
            BigInteger addend = new BigInteger(BITS_BURNIKEL_ZIEGLER - 34, rnd);
            BigInteger v = base.add(addend);

            BigInteger u = v.multiply(BigInteger.valueOf(2 + rnd.nextInt(Short.MAX_VALUE - 1)));

            if(rnd.nextBoolean()) {
                u = u.negate();
            }
            if(rnd.nextBoolean()) {
                v = v.negate();
            }

            int a = 17 + rnd.nextInt(16);
            int b = 1 + rnd.nextInt(16);
            BigInteger w = u.multiply(BigInteger.valueOf(1L << a));
            BigInteger z = v.multiply(BigInteger.valueOf(1L << b));

            BigInteger[] divideResult = u.divideAndRemainder(v);
            divideResult[0] = divideResult[0].multiply(BigInteger.valueOf(1L << (a - b)));
            divideResult[1] = divideResult[1].multiply(BigInteger.valueOf(1L << b));
            BigInteger[] bzResult = w.divideAndRemainder(z);

            if (divideResult[0].compareTo(bzResult[0]) != 0 ||
                    divideResult[1].compareTo(bzResult[1]) != 0) {
                failCount++;
            }
        }

        report("divideLarge", failCount);
    }

    public static void bitCount() {
        int failCount = 0;

        for (int i=0; i<SIZE*10; i++) {
            int x = rnd.nextInt();
            BigInteger bigX = BigInteger.valueOf((long)x);
            int bit = (x < 0 ? 0 : 1);
            int tmp = x, bitCount = 0;
            for (int j=0; j<32; j++) {
                bitCount += ((tmp & 1) == bit ? 1 : 0);
                tmp >>= 1;
            }

            if (bigX.bitCount() != bitCount) {
                //System.err.println(x+": "+bitCount+", "+bigX.bitCount());
                failCount++;
            }
        }
        report("Bit Count", failCount);
    }

    public static void bitLength() {
        int failCount = 0;

        for (int i=0; i<SIZE*10; i++) {
            int x = rnd.nextInt();
            BigInteger bigX = BigInteger.valueOf((long)x);
            int signBit = (x < 0 ? 0x80000000 : 0);
            int tmp = x, bitLength, j;
            for (j=0; j<32 && (tmp & 0x80000000)==signBit; j++)
                tmp <<= 1;
            bitLength = 32 - j;

            if (bigX.bitLength() != bitLength) {
                //System.err.println(x+": "+bitLength+", "+bigX.bitLength());
                failCount++;
            }
        }

        report("BitLength", failCount);
    }

    public static void bitOps(int order) {
        int failCount1 = 0, failCount2 = 0, failCount3 = 0;

        for (int i=0; i<SIZE*5; i++) {
            BigInteger x = fetchNumber(order);
            BigInteger y;

            // Test setBit and clearBit (and testBit)
            if (x.signum() < 0) {
                y = BigInteger.valueOf(-1);
                for (int j=0; j<x.bitLength(); j++)
                    if (!x.testBit(j))
                        y = y.clearBit(j);
            } else {
                y = BigInteger.ZERO;
                for (int j=0; j<x.bitLength(); j++)
                    if (x.testBit(j))
                        y = y.setBit(j);
            }
            if (!x.equals(y))
                failCount1++;

            // 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))
                    y = y.flipBit(j);
            if (!x.equals(y))
                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(order);

            // Test getLowestSetBit()
            int k = x.getLowestSetBit();
            if (x.signum() == 0) {
                if (k != -1)
                    failCount3++;
            } else {
                BigInteger z = x.and(x.negate());
                int j;
                for (j=0; j<z.bitLength() && !z.testBit(j); j++)
                    ;
                if (k != j)
                    failCount3++;
            }
        }
        report("getLowestSetBit for " + order + " bits", failCount3);
    }

    public static void bitwise(int order) {

        // Test identity x^y == x|y &~ x&y
        int failCount = 0;
        for (int i=0; i<SIZE; i++) {
            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 (^ | & ~) for " + order + " bits", failCount);

        // Test identity x &~ y == ~(~x | y)
        failCount = 0;
        for (int i=0; i<SIZE; i++) {
            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 (&~ | ~) for " + order + " bits", failCount);
    }

    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(order);
            int n = Math.abs(rnd.nextInt()%200);

            if (!x.shiftLeft(n).equals
                (x.multiply(BigInteger.valueOf(2L).pow(n))))
                failCount1++;

            BigInteger y[] =x.divideAndRemainder(BigInteger.valueOf(2L).pow(n));
            BigInteger z = (x.signum()<0 && y[1].signum()!=0
                            ? y[0].subtract(BigInteger.ONE)
                            : y[0]);

            BigInteger b = x.shiftRight(n);

            if (!b.equals(z)) {
                System.err.println("Input is "+x.toString(2));
                System.err.println("shift is "+n);

                System.err.println("Divided "+z.toString(2));
                System.err.println("Shifted is "+b.toString(2));
                if (b.toString().equals(z.toString()))
                    System.err.println("Houston, we have a problem.");
                failCount2++;
            }

            if (!x.shiftLeft(n).shiftRight(n).equals(x))
                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(int order) {
        int failCount1 = 0;

        for (int i=0; i<SIZE; i++) {
            BigInteger x = fetchNumber(order).abs();
            while(x.compareTo(BigInteger.valueOf(3L)) != 1)
                x = fetchNumber(order).abs();
            BigInteger z = x.divide(BigInteger.valueOf(2L));
            BigInteger y[] = x.divideAndRemainder(x);
            if (!y[0].equals(BigInteger.ONE)) {
                failCount1++;
                System.err.println("fail1 x :"+x);
                System.err.println("      y :"+y);
            }
            else if (!y[1].equals(BigInteger.ZERO)) {
                failCount1++;
                System.err.println("fail2 x :"+x);
                System.err.println("      y :"+y);
            }

            y = x.divideAndRemainder(z);
            if (!y[0].equals(BigInteger.valueOf(2))) {
                failCount1++;
                System.err.println("fail3 x :"+x);
                System.err.println("      y :"+y);
            }
        }
        report("divideAndRemainder for " + order + " bits", failCount1);
    }

    public static void stringConv() {
        int failCount = 0;

        // Generic string conversion.
        for (int i=0; i<100; i++) {
            byte xBytes[] = new byte[Math.abs(rnd.nextInt())%100+1];
            rnd.nextBytes(xBytes);
            BigInteger x = new BigInteger(xBytes);

            for (int radix=Character.MIN_RADIX; radix < Character.MAX_RADIX; radix++) {
                String result = x.toString(radix);
                BigInteger test = new BigInteger(result, radix);
                if (!test.equals(x)) {
                    failCount++;
                    System.err.println("BigInteger toString: "+x);
                    System.err.println("Test: "+test);
                    System.err.println(radix);
                }
            }
        }

        // String conversion straddling the Schoenhage algorithm crossover
        // threshold, and at twice and four times the threshold.
        for (int k = 0; k <= 2; k++) {
            int factor = 1 << k;
            int upper = factor * BITS_SCHOENHAGE_BASE + 33;
            int lower = upper - 35;

            for (int bits = upper; bits >= lower; bits--) {
                for (int i = 0; i < 50; i++) {
                    BigInteger x = BigInteger.ONE.shiftLeft(bits - 1).or(new BigInteger(bits - 2, rnd));

                    for (int radix = Character.MIN_RADIX; radix < Character.MAX_RADIX; radix++) {
                        String result = x.toString(radix);
                        BigInteger test = new BigInteger(result, radix);
                        if (!test.equals(x)) {
                            failCount++;
                            System.err.println("BigInteger toString: " + x);
                            System.err.println("Test: " + test);
                            System.err.println(radix);
                        }
                    }
                }
            }
        }

        report("String Conversion", failCount);
    }

    public static void byteArrayConv(int order) {
        int failCount = 0;

        for (int i=0; i<SIZE; i++) {
            BigInteger x = fetchNumber(order);
            while (x.equals(BigInteger.ZERO))
                x = fetchNumber(order);
            BigInteger y = new BigInteger(x.toByteArray());
            if (!x.equals(y)) {
                failCount++;
                System.err.println("orig is "+x);
                System.err.println("new is "+y);
            }
        }
        report("Array Conversion for " + order + " bits", failCount);
    }

    public static void modInv(int order) {
        int failCount = 0, successCount = 0, nonInvCount = 0;

        for (int i=0; i<SIZE; i++) {
            BigInteger x = fetchNumber(order);
            while(x.equals(BigInteger.ZERO))
                x = fetchNumber(order);
            BigInteger m = fetchNumber(order).abs();
            while(m.compareTo(BigInteger.ONE) != 1)
                m = fetchNumber(order).abs();

            try {
                BigInteger inv = x.modInverse(m);
                BigInteger prod = inv.multiply(x).remainder(m);

                if (prod.signum() == -1)
                    prod = prod.add(m);

                if (prod.equals(BigInteger.ONE))
                    successCount++;
                else
                    failCount++;
            } catch(ArithmeticException e) {
                nonInvCount++;
            }
        }
        report("Modular Inverse for " + order + " bits", failCount);
    }

    public static void modExp(int order1, int order2) {
        int failCount = 0;

        for (int i=0; i<SIZE/10; i++) {
            BigInteger m = fetchNumber(order1).abs();
            while(m.compareTo(BigInteger.ONE) != 1)
                m = fetchNumber(order1).abs();
            BigInteger base = fetchNumber(order2);
            BigInteger exp = fetchNumber(8).abs();

            BigInteger z = base.modPow(exp, m);
            BigInteger w = base.pow(exp.intValue()).mod(m);
            if (!z.equals(w)) {
                System.err.println("z is "+z);
                System.err.println("w is "+w);
                System.err.println("mod is "+m);
                System.err.println("base is "+base);
                System.err.println("exp is "+exp);
                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(int order) {
        int failCount = 0;

        for (int i=0; i<10; i++) {
            BigInteger m = new BigInteger(100, 5, rnd);
            while(m.compareTo(BigInteger.ONE) != 1)
                m = new BigInteger(100, 5, rnd);
            BigInteger exp = m.subtract(BigInteger.ONE);
            BigInteger base = fetchNumber(order).abs();
            while(base.compareTo(m) != -1)
                base = fetchNumber(order).abs();
            while(base.equals(BigInteger.ZERO))
                base = fetchNumber(order).abs();

            BigInteger one = base.modPow(exp, m);
            if (!one.equals(BigInteger.ONE)) {
                System.err.println("m is "+m);
                System.err.println("base is "+base);
                System.err.println("exp is "+exp);
                failCount++;
            }
        }
        report("Exponentiation II for " + order + " bits", failCount);
    }

    private static final int[] mersenne_powers = {
        521, 607, 1279, 2203, 2281, 3217, 4253, 4423, 9689, 9941, 11213, 19937,
        21701, 23209, 44497, 86243, 110503, 132049, 216091, 756839, 859433,
        1257787, 1398269, 2976221, 3021377, 6972593, 13466917 };

    private static final long[] carmichaels = {
      561,1105,1729,2465,2821,6601,8911,10585,15841,29341,41041,46657,52633,
      62745,63973,75361,101101,115921,126217,162401,172081,188461,252601,
      278545,294409,314821,334153,340561,399001,410041,449065,488881,512461,
      225593397919L };

    // Note: testing the larger ones takes too long.
    private static final int NUM_MERSENNES_TO_TEST = 7;
    // Note: this constant used for computed Carmichaels, not the array above
    private static final int NUM_CARMICHAELS_TO_TEST = 5;

    private static final String[] customer_primes = {
        "120000000000000000000000000000000019",
        "633825300114114700748351603131",
        "1461501637330902918203684832716283019651637554291",
        "779626057591079617852292862756047675913380626199",
        "857591696176672809403750477631580323575362410491",
        "910409242326391377348778281801166102059139832131",
        "929857869954035706722619989283358182285540127919",
        "961301750640481375785983980066592002055764391999",
        "1267617700951005189537696547196156120148404630231",
        "1326015641149969955786344600146607663033642528339" };

    private static final BigInteger ZERO = BigInteger.ZERO;
    private static final BigInteger ONE = BigInteger.ONE;
    private static final BigInteger TWO = new BigInteger("2");
    private static final BigInteger SIX = new BigInteger("6");
    private static final BigInteger TWELVE = new BigInteger("12");
    private static final BigInteger EIGHTEEN = new BigInteger("18");

    public static void prime() {
        BigInteger p1, p2, c1;
        int failCount = 0;

        // Test consistency
        for(int i=0; i<10; i++) {
            p1 = BigInteger.probablePrime(100, rnd);
            if (!p1.isProbablePrime(100)) {
                System.err.println("Consistency "+p1.toString(16));
                failCount++;
            }
        }

        // Test some known Mersenne primes (2^n)-1
        // The array holds the exponents, not the numbers being tested
        for (int i=0; i<NUM_MERSENNES_TO_TEST; i++) {
            p1 = new BigInteger("2");
            p1 = p1.pow(mersenne_powers[i]);
            p1 = p1.subtract(BigInteger.ONE);
            if (!p1.isProbablePrime(100)) {
                System.err.println("Mersenne prime "+i+ " failed.");
                failCount++;
            }
        }

        // Test some primes reported by customers as failing in the past
        for (int i=0; i<customer_primes.length; i++) {
            p1 = new BigInteger(customer_primes[i]);
            if (!p1.isProbablePrime(100)) {
                System.err.println("Customer prime "+i+ " failed.");
                failCount++;
            }
        }

        // Test some known Carmichael numbers.
        for (int i=0; i<carmichaels.length; i++) {
            c1 = BigInteger.valueOf(carmichaels[i]);
            if(c1.isProbablePrime(100)) {
                System.err.println("Carmichael "+i+ " reported as prime.");
                failCount++;
            }
        }

        // Test some computed Carmichael numbers.
        // Numbers of the form (6k+1)(12k+1)(18k+1) are Carmichael numbers if
        // each of the factors is prime
        int found = 0;
        BigInteger f1 = new BigInteger(40, 100, rnd);
        while (found < NUM_CARMICHAELS_TO_TEST) {
            BigInteger k = null;
            BigInteger f2, f3;
            f1 = f1.nextProbablePrime();
            BigInteger[] result = f1.subtract(ONE).divideAndRemainder(SIX);
            if (result[1].equals(ZERO)) {
                k = result[0];
                f2 = k.multiply(TWELVE).add(ONE);
                if (f2.isProbablePrime(100)) {
                    f3 = k.multiply(EIGHTEEN).add(ONE);
                    if (f3.isProbablePrime(100)) {
                        c1 = f1.multiply(f2).multiply(f3);
                        if (c1.isProbablePrime(100)) {
                            System.err.println("Computed Carmichael "
                                               +c1.toString(16));
                            failCount++;
                        }
                        found++;
                    }
                }
            }
            f1 = f1.add(TWO);
        }

        // Test some composites that are products of 2 primes
        for (int i=0; i<50; i++) {
            p1 = BigInteger.probablePrime(100, rnd);
            p2 = BigInteger.probablePrime(100, rnd);
            c1 = p1.multiply(p2);
            if (c1.isProbablePrime(100)) {
                System.err.println("Composite failed "+c1.toString(16));
                failCount++;
            }
        }

        for (int i=0; i<4; i++) {
            p1 = BigInteger.probablePrime(600, rnd);
            p2 = BigInteger.probablePrime(600, rnd);
            c1 = p1.multiply(p2);
            if (c1.isProbablePrime(100)) {
                System.err.println("Composite failed "+c1.toString(16));
                failCount++;
            }
        }

        report("Prime", failCount);
    }

    private static final long[] primesTo100 = {
        2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97
    };

    private static final long[] aPrimeSequence = {
        1999999003L, 1999999013L, 1999999049L, 1999999061L, 1999999081L,
        1999999087L, 1999999093L, 1999999097L, 1999999117L, 1999999121L,
        1999999151L, 1999999171L, 1999999207L, 1999999219L, 1999999271L,
        1999999321L, 1999999373L, 1999999423L, 1999999439L, 1999999499L,
        1999999553L, 1999999559L, 1999999571L, 1999999609L, 1999999613L,
        1999999621L, 1999999643L, 1999999649L, 1999999657L, 1999999747L,
        1999999763L, 1999999777L, 1999999811L, 1999999817L, 1999999829L,
        1999999853L, 1999999861L, 1999999871L, 1999999873
    };

    public static void nextProbablePrime() throws Exception {
        int failCount = 0;
        BigInteger p1, p2, p3;
        p1 = p2 = p3 = ZERO;

        // First test nextProbablePrime on the low range starting at zero
        for (int i=0; i<primesTo100.length; i++) {
            p1 = p1.nextProbablePrime();
            if (p1.longValue() != primesTo100[i]) {
                System.err.println("low range primes failed");
                System.err.println("p1 is "+p1);
                System.err.println("expected "+primesTo100[i]);
                failCount++;
            }
        }

        // Test nextProbablePrime on a relatively small, known prime sequence
        p1 = BigInteger.valueOf(aPrimeSequence[0]);
        for (int i=1; i<aPrimeSequence.length; i++) {
            p1 = p1.nextProbablePrime();
            if (p1.longValue() != aPrimeSequence[i]) {
                System.err.println("prime sequence failed");
                failCount++;
            }
        }

        // Next, pick some large primes, use nextProbablePrime to find the
        // next one, and make sure there are no primes in between
        for (int i=0; i<100; i+=10) {
            p1 = BigInteger.probablePrime(50 + i, rnd);
            p2 = p1.add(ONE);
            p3 = p1.nextProbablePrime();
            while(p2.compareTo(p3) < 0) {
                if (p2.isProbablePrime(100)){
                    System.err.println("nextProbablePrime failed");
                    System.err.println("along range "+p1.toString(16));
                    System.err.println("to "+p3.toString(16));
                    failCount++;
                    break;
                }
                p2 = p2.add(ONE);
            }
        }

        report("nextProbablePrime", failCount);
    }

    public static void serialize() throws Exception {
        int failCount = 0;

        String bitPatterns[] = {
             "ffffffff00000000ffffffff00000000ffffffff00000000",
             "ffffffffffffffffffffffff000000000000000000000000",
             "ffffffff0000000000000000000000000000000000000000",
             "10000000ffffffffffffffffffffffffffffffffffffffff",
             "100000000000000000000000000000000000000000000000",
             "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
            "-ffffffff00000000ffffffff00000000ffffffff00000000",
            "-ffffffffffffffffffffffff000000000000000000000000",
            "-ffffffff0000000000000000000000000000000000000000",
            "-10000000ffffffffffffffffffffffffffffffffffffffff",
            "-100000000000000000000000000000000000000000000000",
            "-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
        };

        for(int i = 0; i < bitPatterns.length; i++) {
            BigInteger b1 = new BigInteger(bitPatterns[i], 16);
            BigInteger b2 = null;

            File f = new File("serialtest");

            try (FileOutputStream fos = new FileOutputStream(f)) {
                try (ObjectOutputStream oos = new ObjectOutputStream(fos)) {
                    oos.writeObject(b1);
                    oos.flush();
                }

                try (FileInputStream fis = new FileInputStream(f);
                     ObjectInputStream ois = new ObjectInputStream(fis))
                {
                    b2 = (BigInteger)ois.readObject();
                }

                if (!b1.equals(b2) ||
                    !b1.equals(b1.or(b2))) {
                    failCount++;
                    System.err.println("Serialized failed for hex " +
                                       b1.toString(16));
                }
            }
            f.delete();
        }

        for(int i=0; i<10; i++) {
            BigInteger b1 = fetchNumber(rnd.nextInt(100));
            BigInteger b2 = null;
            File f = new File("serialtest");
            try (FileOutputStream fos = new FileOutputStream(f)) {
                try (ObjectOutputStream oos = new ObjectOutputStream(fos)) {
                    oos.writeObject(b1);
                    oos.flush();
                }

                try (FileInputStream fis = new FileInputStream(f);
                     ObjectInputStream ois = new ObjectInputStream(fis))
                {
                    b2 = (BigInteger)ois.readObject();
                }
            }

            if (!b1.equals(b2) ||
                !b1.equals(b1.or(b2)))
                failCount++;
            f.delete();
        }

        report("Serialize", failCount);
    }

    /**
     * Main to interpret arguments and run several tests.
     *
     * Up to three arguments may be given to specify the SIZE of BigIntegers
     * used for call parameters 1, 2, and 3. The SIZE is interpreted as
     * the maximum number of decimal digits that the parameters will have.
     *
     */
    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(order1);   // small numbers
        arithmetic(order3);   // Karatsuba range
        arithmetic(order4);   // Toom-Cook / Burnikel-Ziegler range

        divideAndRemainder(order1);   // small numbers
        divideAndRemainder(order3);   // Karatsuba range
        divideAndRemainder(order4);   // Toom-Cook / Burnikel-Ziegler range

        pow(order1);
        pow(order3);
        pow(order4);

        square(ORDER_MEDIUM);
        square(ORDER_KARATSUBA_SQUARE);
        square(ORDER_TOOM_COOK_SQUARE);

        bitCount();
        bitLength();
        bitOps(order1);
        bitwise(order1);

        shift(order1);

        byteArrayConv(order1);

        modInv(order1);   // small numbers
        modInv(order3);   // Karatsuba range
        modInv(order4);   // Toom-Cook / Burnikel-Ziegler range

        modExp(order1, order2);
        modExp2(order1);

        stringConv();
        serialize();

        multiplyLarge();
        squareLarge();
        divideLarge();

        if (failure)
            throw new RuntimeException("Failure in BigIntegerTest.");
    }

    /*
     * Get a random or boundary-case number. This is designed to provide
     * a lot of numbers that will find failure points, such as max sized
     * numbers, empty BigIntegers, etc.
     *
     * If order is less than 2, order is changed to 2.
     */
    private static BigInteger fetchNumber(int order) {
        boolean negative = rnd.nextBoolean();
        int numType = rnd.nextInt(7);
        BigInteger result = null;
        if (order < 2) order = 2;

        switch (numType) {
            case 0: // Empty
                result = BigInteger.ZERO;
                break;

            case 1: // One
                result = BigInteger.ONE;
                break;

            case 2: // All bits set in number
                int numBytes = (order+7)/8;
                byte[] fullBits = new byte[numBytes];
                for(int i=0; i<numBytes; i++)
                    fullBits[i] = (byte)0xff;
                int excessBits = 8*numBytes - order;
                fullBits[0] &= (1 << (8-excessBits)) - 1;
                result = new BigInteger(1, fullBits);
                break;

            case 3: // One bit in number
                result = BigInteger.ONE.shiftLeft(rnd.nextInt(order));
                break;

            case 4: // Random bit density
                byte[] val = new byte[(order+7)/8];
                int iterations = rnd.nextInt(order);
                for (int i=0; i<iterations; i++) {
                    int bitIdx = rnd.nextInt(order);
                    val[bitIdx/8] |= 1 << (bitIdx%8);
                }
                result = new BigInteger(1, val);
                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);
        }

        if (negative)
            result = result.negate();

        return result;
    }

    static void report(String testName, int failCount) {
        System.err.println(testName+": " +
                           (failCount==0 ? "Passed":"Failed("+failCount+")"));
        if (failCount > 0)
            failure = true;
    }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java BigIntegerTest.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.