|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- 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<Worker> 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;
- }
- }
|