/* * Copyright (c) 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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. */ import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.math.BigInteger; import java.util.HashSet; //I would like to see the functional tests. // //We can take the list of prime numbers [1] as set P, and then check: // a) numbers in intersect([2;N), P) return isProbablyPrime=true in more //than >(1 - 1/2^cert) cases; // b) all numbers in difference([2;N), P) return isProbablyPrime=false //--- //Wait, this is one is wrong (too general). I meant to say all numbers in //[2;N) that return isProbablyPrime=false are not in P. // //N > 50.000.000 would sound convincing. // //I need this list for another reason, so I had preprocessed the first 50M //primes here: // http://cr.openjdk.java.net/~shade/scratch/primes-50M.txt.xz //--- //Plus the certainty is capped at 100 if the bit length of the big int < 100 //(which is the case for the first 50M primes). For large bit lengths it is //even less (capped at 4 for > 1024). (IIUC it is (1 - 1/4^N) for N iterations //[1], for the impl N = certainty/2.) // //[1] http://mathworld.wolfram.com/Rabin-MillerStrongPseudoprimeTest.html public class PrimeTest { public static void main(String[] args) throws Throwable { File primesFile = new File(args[0]); int upperBound = Integer.valueOf(args[1]); int certainty = Integer.valueOf(args[2]); System.out.println("Primes: "+primesFile+"\nN = "+upperBound+ "\ncertainty = "+certainty); boolean primeTest = checkPrime(primesFile, upperBound, certainty); System.out.println("Prime test = "+primeTest); boolean notPrimeTest = checkNotPrime(primesFile, upperBound, certainty); System.out.println("Not-prime test = "+notPrimeTest); if (!primeTest || !notPrimeTest) { throw new Exception("Test failed!"); } System.out.println("Test succeeded!"); } /** * Verifies whether the fraction of probable primes detected in the range * [2,upperBound) is at least 1 - 1/2^certainty. * * @return true if and only if the test succeeds */ private static boolean checkPrime(File primesFile, int upperBound, int certainty) throws FileNotFoundException, IOException { BufferedReader reader = new BufferedReader(new FileReader(primesFile)); BigInteger bigBound = BigInteger.valueOf(upperBound); int total = 0; int prime = 0; String line; while ((line = reader.readLine()) != null) { BigInteger bigInt = new BigInteger(line); if (bigInt.compareTo(bigBound) >= 0) { //System.out.println("Break at "+bigInt); break; } total++; if (bigInt.isProbablePrime(certainty)) { prime++; } } System.out.println(prime+" probable primes out of "+total+" candidates"); // Success if p/t >= 1 - 1/2^certainty // or (p/t)*2^c >= 2^c - 1 // or p*2^c >= t*(2^c - 1) BigInteger p = BigInteger.valueOf(prime); BigInteger t = BigInteger.valueOf(total); BigInteger twoToTheC = BigInteger.ONE.shiftLeft(certainty); BigInteger twoToTheCMinusOne = twoToTheC.subtract(BigInteger.ONE); BigInteger left = p.multiply(twoToTheC); BigInteger right = t.multiply(twoToTheCMinusOne); return left.compareTo(right) >= 0; } /** * Verifies whether all {@code BigInteger}s in the range [2,upperBound) for * which {@code isProbablePrime()} returns {@code false} are not * prime numbers. * * @return true if and only if the test succeeds */ private static boolean checkNotPrime(File primesFile, int upperBound, int certainty) throws FileNotFoundException, IOException { BufferedReader reader = new BufferedReader(new FileReader(primesFile)); HashSet primes = new HashSet(upperBound); String line; while ((line = reader.readLine()) != null) { Integer primeValue = Integer.valueOf(line); if (primeValue >= upperBound) { //System.out.println("Break at "+primeValue); break; } primes.add(primeValue); } reader.close(); boolean result = true; for (int i = 2; i < upperBound; i++) { BigInteger bigInt = BigInteger.valueOf(i); if (!bigInt.isProbablePrime(certainty) && primes.contains(Integer.valueOf(i))) { result = false; break; } } return result; } }