The professional, friendly Java community. 21,500 members and growing!

The Java Programming Forums are a community of Java programmers from all around the World. Our members have a wide range of skills and they all have one thing in common: A passion to learn and code Java. We invite beginner Java programmers right through to Java professionals to post here and share your knowledge. Become a part of the community, help others, expand your knowledge of Java and enjoy talking with like minded people. Registration is quick and best of all free. We look forward to meeting you.

Java Tip Jan 22, 2011 - Primality Tests

Introduction

Determining if a number is prime is very important for many applications. While the main application is in cryptography, there are other applications which require prime numbers.

Probabilistic tests are most useful for large prime numbers. Small prime numbers can be tested quickly enough using a naive primality test. The Miller-Rabin primality test is one of the most popular probabilistic tests to determine if a number is composite or probably prime.

In this tip, code for a naive primality test as well as a Miller-Rabin primality test are provided.

The Naive Primality Test

The naive primality test works by testing if that number is divisible by any other number. There are 2 main optimizations which are used to speed up the primality tests:

1. Every even integer greater than 2 is not prime.
2. The maximum number you have to test goes up to sqrt(number).

The Miller-Rabin primality test works using some properties of advanced number theory which goes above a lot of other people's head (definitely above mine). If you want to learn how it works, see Wikipedia: Miller-Rabin Primality Test

For small numbers, using the Naive test is faster (~3 times faster). Even so, the Miller-Rabin test was able to test small numbers quickly and efficiently. The interesting results are those for large numbers. The Miller-Rabin test was ~7 times faster for moderately large numbers. To put this into perspective:
Generally for cryptography, most algorithms use ~256 bits or more. Here do the limitations of how I implemented the algorithm, we only have 32 bits (technically 31 because Java doesn't let you have unsigned values). These performance gains will grow exponentially with with larger and larger numbers. Just for fun, I ran the Miller-Rabin test for the full range of all integers (0 to 2^31-1) and it took 34.44 minutes. I didn't want to run the same range using the Naive test, but using the above results I think it's reasonable to conclude that it would have taken ~4 hours to complete that test.

So how does the Miller-Rabin test fair on accuracy?
1. If the test marks a number composite, it is composite (no questions asked).
2. The theoretical chance that it will incorrectly guess that a number is prime is 4^(-k), where k is the number of iterations. It's difficult to derive a direct k-value from my code because I used a random number generator and didn't check for duplicates. However, for large numbers being tested, it's reasonable to conclude that the k-value is ~5 for the parameters I used. This results in a theoretical chance of incorrectly labeling something as prime at 0.09765625%. In practice, this chance is actually a lot smaller. I have been able to run this code over billions, perhaps even trillions of numbers and have yet to encounter the algorithm labeling the number as prime incorrectly.

Conclusion

In conclusion, I hope this code will be useful to someone (likely just as a reference). The major pit-fall of this code is that it doesn't support big integers. There is also one major speed improvement that can be made, and that's replacing the current integer power code with a FFT (Fast-Fourier Transform) algorithm. This last suggestion can speed up the algorithm by an order of magnitude.

The default Java BigInteger class also supports a probabilistic primality test (likely implemented using the Solovay-Strassen primality test). This test has the problem of having an accuracy of 2^-k. While still quite good, it's not nearly as good as the the Miller-Rabin test. Also, the Miller-Rabin test will never incorrectly label composite numbers while the Solovay-Strassen test has a chance of incorrectly labeling prime or composite numbers. I believe both tests have the same running time if comparing to my implementation. I'm not sure if the Solovay-Strassen could also use a FFT to improve it's performance, though I wouldn't doubt it.

Re: Java Tip Jan 22, 2011 - Primality Tests

In this case, there's no point because I'm able to compute the exponentiation in O(log(n)), and from what I understand about FFT's, we're both using similar methods (divide & conquer). Also, for other math operations, the hardware is always going to be faster than anything I can write in software.

However, in http://www.javaprogrammingforums.com...primality.html, I implemented the same algorithm using Java's BigInteger class. I can't remember exactly what algorithm they use internally for multiplication/division/exponentiation, but I believe they do it naively, which is O(n^2), where-as a FFT is O(n log(n)), which is considerably faster (for longer numbers, at least).