You are on page 1of 1

5.3.

NUMBER THEORY 
c Steven & Felix, NUS

Prime number is an important topic in number theory and the source for many programming
problems1 . In this section, we will discuss algorithms involving prime numbers.

Optimized Prime Testing Function

The first algorithm presented in this section is for testing whether a given natural number N is
prime, i.e. bool isPrime(N). The most naı̈ve version is to test by definition, i.e. test if N is
divisible by divisor ∈ [2 . . . N -1]. This of course works, but runs in O(N ) – in terms of number of
divisions. This is not the best way and there are several possible improvements.

The first improvement is to test if N is divisible by a divisor ∈ [2 . . . N ], i.e. we stop when

the divisor is already greater than N . This is because if N is divisible by p, then N = p × q. If

q were smaller than p, then q or a prime factor of q would have divided N earlier. This is O( N )
which is already much faster than previous version, but can still be improved to be twice faster.

The second improvement is to test if N is divisible by divisor ∈ [3, 5, 7 . . . N ], i.e. we only

test odd numbers up to N . This is because there is only one even prime number, i.e. number 2,
√ √
which can be tested separately. This is O( N /2), which is also O( N ).
The third improvement2 which is already good enough for contest problems is to test if N is

divisible by prime divisors ≤ N . This is because if a prime number X cannot divide N , then

there is no point testing whether multiples of X divide N or not. This is faster than O( N ) which
√ 
is about O(|#primes ≤ N |). For example, there are 500 odd numbers in [1 . . . (106 )], but there
are only 168 primes in the same range. The number of primes ≤ M – denoted by π(M ) – is bounded
√ √
by O(M/(ln(M ) − 1)), so the complexity of this prime testing function is about O( N / ln( N )).
The code is shown in the next discussion below.

Sieve of Eratosthenes: Generating List of Prime Numbers

If we want to generate a list of prime numbers between range [0 . . . N ], there is a better algorithm
than testing each number in the range whether it is a prime or not. The algorithm is called ‘Sieve
of Eratosthenes’ invented by Eratosthenes of Alexandria. It works as follows.
First, it sets all numbers in the range to be ‘probably prime’ but set numbers 0 and 1 to be
not prime. Then, it takes 2 as prime and crosses out all multiples3 of 2 starting from 2 × 2 = 4,
6, 8, 10, ... until it the multiple is greater than N . Then it takes the next non-crossed number 3
as a prime and crosses out all multiples of 3 starting from 3 × 3 = 9, 12, 15, 18, .... Then it takes
5 and crosses out all multiples of 5 starting from 5 × 5 = 25, 30, 35, 40, .... After that, whatever
left uncrossed within the range [0 . . . N ] are primes. This algorithm does approximately (N × (1/2
+ 1/3 + 1/5 + 1/7 + ... + 1/last prime in range ≤ N )) operations. Using ‘sum of reciprocals of
primes up to n’, we end up with the time complexity of roughly O(N log log N ) [44].
Since generating a list of small primes ≤ 10K using the sieve is fast (our library code below can
go up to 107 under contest setting), we opt sieve for smaller primes and reserve optimized prime
testing function for larger primes – see previous discussion. The combined code is as follows:

1
In real life, large primes are used in cryptography because it is hard to factor a number xy into x × y when both
are relatively prime.
2
This is a bit recursive – testing whether a number is a prime by using another (smaller) prime numbers. But the
reason should be obvious after reading the next section.
3
Common sub-optimal implementation is to start from 2 × i instead of i × i, but the difference is not that much.

95

You might also like