Probably, you won't be able to find it in reasonable time. It takes really a lot of time.
Find all prime numbers
If we would keep this algorithm run for few ethernities, we would maybe find the longest prime number so far discovered. This algorithm is the basic version, not optimized and thus very very slow type of algorithm.
public class PrimeNumber {
@Test
public void findsAllPrimeNumbers() {
findAllPrimeNumbers(ZERO);
}
private boolean isPrimeNumber(BigInteger number) {
if (number.equals(ZERO) || number.equals(ONE)) return false;
for (BigInteger i = BigInteger.valueOf(2); i.compareTo(number.subtract(ONE)) < 0; i = i.add(ONE)) {
BigInteger remainder = number.remainder(i);
if (remainder.equals(ZERO)) return false;
}
return true;
}
private void findAllPrimeNumbers(BigInteger startFrom) {
BigInteger runningNumber = startFrom;
while (true) {
if (isPrimeNumber(runningNumber))
System.out.println("FOUND: " + runningNumber);
runningNumber = runningNumber.add(ONE);
}
}
}
What would happen when we run the findAllPrimeNumbers with lests say 999999999999999999999999999999999?
We wouldn't get much far. It takes too much time to find number in single threaded process.
Find prime numbers using multi threaded code
Another logical implication to speed up the search process is to use multiple CPUs to find the prime numbers. Lets say we want to create batches of 100 numbers and use 100 threads to find the numbers. We could write code like this to do it.
import org.junit.Assert;
import org.junit.Test;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicReference;
import static java.math.BigInteger.ONE;
import static java.math.BigInteger.ZERO;
public class PrimeNumber {
@Test
public void findMultiThreaded() throws ExecutionException, InterruptedException, TimeoutException {
// findAllPrimeNumbersMultiTheaded(ZERO);
findAllPrimeNumbersMultiTheaded(new BigInteger("10000000"));
}
class FindPrimeNumber implements Callable<BigInteger> {
private BigInteger candidate;
public FindPrimeNumber(BigInteger candidate) {
this.candidate = candidate;
}
@Override
public BigInteger call() throws Exception {
return isPrimeNumber(candidate);
}
private BigInteger isPrimeNumber(BigInteger number) {
if (number.equals(ZERO) || number.equals(ONE)) return ZERO;
for (BigInteger i = BigInteger.valueOf(2); i.compareTo(number.subtract(ONE)) < 0; i = i.add(ONE)) {
BigInteger remainder = number.remainder(i);
if (remainder.equals(ZERO)) return ZERO;
}
return number;
}
}
private void findAllPrimeNumbersMultiTheaded(BigInteger startFrom) throws ExecutionException, InterruptedException, TimeoutException {
ExecutorService executorService = Executors.newFixedThreadPool(1000);
BigInteger runningNumber = startFrom;
int counter = 0;
int batchSize = 100;
List<Callable<BigInteger>> tasks = new ArrayList<>();
while (counter < batchSize) {
tasks.add(new FindPrimeNumber(runningNumber));
runningNumber = runningNumber.add(BigInteger.ONE);
counter++;
if (counter == batchSize) {
List<Future<BigInteger>> futures = executorService.invokeAll(tasks);
for (Future<BigInteger> future : futures) {
BigInteger foundNumber = future.get();
if (!foundNumber.equals(ZERO)) {
System.out.println("PRIME NUMBER:" + foundNumber);
}
}
counter = 0;
tasks = new ArrayList<>();
}
}
}
}
Here is a sample output this program produces. You can experiment with size of batch and number of threads if you like this brute force approach.
PRIME NUMBER:10000019
PRIME NUMBER:10000079
PRIME NUMBER:10000103
PRIME NUMBER:10000121
PRIME NUMBER:10000139
PRIME NUMBER:10000141
PRIME NUMBER:10000169
PRIME NUMBER:10000189
PRIME NUMBER:10000223
PRIME NUMBER:10000229
PRIME NUMBER:10000247
PRIME NUMBER:10000253
PRIME NUMBER:10000261
PRIME NUMBER:10000271
Be aware, if you are too eager with amount of threads and batch size, you will get this exception.
java.lang.OutOfMemoryError: unable to create new native thread