I am trying to find the fastest way to check whether a given number is prime or not (in Java). Below are several primality testing methods I came up with. Is there any better way than the second implementation(isPrime2)?
public class Prime {
public static boolean isPrime1(int n) {
if (n <= 1) {
return false;
}
if (n == 2) {
return true;
}
for (int i = 2; i <= Math.sqrt(n) + 1; i++) {
if (n % i == 0) {
return false;
}
}
return true;
}
public static boolean isPrime2(int n) {
if (n <= 1) {
return false;
}
if (n == 2) {
return true;
}
if (n % 2 == 0) {
return false;
}
for (int i = 3; i <= Math.sqrt(n) + 1; i = i + 2) {
if (n % i == 0) {
return false;
}
}
return true;
}
}
public class PrimeTest {
public PrimeTest() {
}
@Test
public void testIsPrime() throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
Prime prime = new Prime();
TreeMap<Long, String> methodMap = new TreeMap<Long, String>();
for (Method method : Prime.class.getDeclaredMethods()) {
long startTime = System.currentTimeMillis();
int primeCount = 0;
for (int i = 0; i < 1000000; i++) {
if ((Boolean) method.invoke(prime, i)) {
primeCount++;
}
}
long endTime = System.currentTimeMillis();
Assert.assertEquals(method.getName() + " failed ", 78498, primeCount);
methodMap.put(endTime - startTime, method.getName());
}
for (Entry<Long, String> entry : methodMap.entrySet()) {
System.out.println(entry.getValue() + " " + entry.getKey() + " Milli seconds ");
}
}
}
You took the first step in eliminating all multiples of 2.
However, why did you stop there? you could have eliminated all multiples of 3 except for 3, all multiples of 5 except for 5, etc.
When you follow this reasoning to its conclusion, you get the Sieve of Eratosthenes.
Your algorithm will work well for reasonably small numbers. For big numbers, advanced algorithms should be used (based for example on elliptic curves). Another idea will be to use some "pseuso-primes" test. These will test quickly that a number is a prime, but they aren't 100% accurate. However, they can help you rule out some numbers quicker than with your algorithm.
Finally, although the compiler will probably optimise this for you, you should write:
This is the most elegant way:
Java 1.4+. No imports needed.
So short. So beautiful.
Dependent on the length of the number you need to test you could precompute a list of prime numbers for small values (n < 10^6), which is used first, if the asked number is within this range. This is of course the fastest way. Like mentioned in other answers the Sieve of Eratosthenes is the preferred method to generate such a precomputed list.
If your numbers are larger than this, you can use the primality test of Rabin. Rabin primality test
Here's another way:
and
BigInteger's isProbablePrime(...)
is valid for all 32 bitint
's.EDIT
Note that
isProbablePrime(certainty)
does not always produce the correct answer. When the certainty is on the low side, it produces false positives, as @dimo414 mentioned in the comments.Unfortunately, I could not find the source that claimed
isProbablePrime(certainty)
is valid for all (32-bit)int
's (given enough certainty!).So I performed a couple of tests. I created a
BitSet
of sizeInteger.MAX_VALUE/2
representing all uneven numbers and used a prime sieve to find all primes in the range1..Integer.MAX_VALUE
. I then looped fromi=1..Integer.MAX_VALUE
to test that everynew BigInteger(String.valueOf(i)).isProbablePrime(certainty) == isPrime(i)
.For certainty 5 and 10,
isProbablePrime(...)
produced false positives along the line. But withisProbablePrime(15)
, no test failed.Here's my test rig:
which I ran by doing:
The generating of the primes took ~30 sec on my machine. And the actual test of all
i
in1..Integer.MAX_VALUE
took around 2 hours and 15 minutes.Take a look at the AKS primality test (and its various optimizations). It is a deterministic primality test that runs in polynomial time.
There is an implementation of the algorithm in Java from the University of Tuebingen (Germany) here