133 lines
4.4 KiB
Java
133 lines
4.4 KiB
Java
|
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;
|
||
|
}
|
||
|
}
|