import java.math.BigInteger; import java.util.LinkedList; import java.util.List; import java.util.Random; public class Prime { /** * Calculates the integer square root of a number. * Source: https://stackoverflow.com/questions/4407839/how-can-i-find-the-square-root-of-a-java-biginteger/13023513#13023513 * * @param x the number * @return the square root */ private static BigInteger sqrt(BigInteger x) { BigInteger div = BigInteger.ZERO.setBit(x.bitLength()/2); BigInteger div2 = div; // Loop until we hit the same value twice in a row, or wind // up alternating. for(;;) { BigInteger y = div.add(x.divide(div)).shiftRight(1); if (y.equals(div) || y.equals(div2)) return y; div2 = div; div = y; } } /** * Checks, whether a number is a prime or not. Uses naive implementation accelerated by multithreading. * * @param candidate the number to check * @return the boolean */ private static boolean isPrime(BigInteger candidate) { // Check special candidate values 0, 1, 2 and even if (candidate.compareTo(BigInteger.ZERO) == 0 // candidate == 0 || candidate.compareTo(BigInteger.ONE) == 0) { // candidate == 1) return false; } if (candidate.compareTo(BigInteger.valueOf(2)) == 0) { // candidate == 2 return true; } else if (candidate.mod(BigInteger.valueOf(2)).equals(BigInteger.ZERO)) { // candidate is even return false; } // Divide interval into segments, one for each cpu core int cores = Runtime.getRuntime().availableProcessors(); BigInteger max = sqrt(candidate).add(BigInteger.ONE); BigInteger min = BigInteger.valueOf(3); BigInteger step = max.subtract(min).divide(BigInteger.valueOf(cores)); BigInteger remainder = max.subtract(min).mod(BigInteger.valueOf(cores)); int i = 0; List workers = new LinkedList<>(); while (i < cores) { BigInteger num = step; if (remainder.compareTo(BigInteger.ZERO) == 1) { // remainder > 0 num = num.add(BigInteger.ONE); remainder = remainder.subtract(BigInteger.ONE); } num = num.subtract(BigInteger.ONE); if (num.compareTo(BigInteger.ZERO) >= 0) { workers.add(new Worker(candidate, min, min.add(num), "Thread " + i)); workers.get(i).start(); min = min.add(num).add(BigInteger.ONE); } i++; if (min.compareTo(max) > 0) { break; } } // Wait for workers to complete boolean stop = false; boolean isPrime = true; while (!stop) { i = 0; while (i < workers.size()) { Worker w = workers.get(i); try { w.join(500); } catch (InterruptedException ex) { ex.printStackTrace(); } if (w.hasFinished()) { if (!w.isPrime()) { isPrime = false; stop = true; break; } else { // This worker is done, remove it from the list workers.remove(w); if (workers.isEmpty()) { stop = true; break; } } } i++; } } // Stop workers for (Worker w: workers) { w.interrupt(); } return isPrime; } /** * Generates a guaranteed prime of the given length. * * @param bits binary length of the prime to generate * @return prime number */ public static BigInteger generate(int bits) { Random rng = new Random(); BigInteger candidate = new BigInteger(bits, rng); int i = 0; while (!isPrime(candidate)){ //System.out.println("Not a prime: " + candidate); candidate = new BigInteger(bits, rng); i++; } //System.out.println("Found prime after " + i + " tries: " + candidate); return candidate; } }