Primes generation
The classic approach at generating primes less than a certain value \( N \) is the Sieve of Eratosthenes. The algorithm simply proceeds by dropping all the numbers generated by repeatedly adding a number (thus multiples of the first number).
The code above features two optimization:
- Even numbers are computed beforehand while odd numbers proceed skipping the even ones
- Only numbers below \( \sqrt{N} \) are considered since any other greater number would be useless to compute by recursively adding it multiple times
A quick computational analysis shows that the running time is
\[\frac{N}{2} + \frac{N}{3} + \frac{N}{5} + \ldots + \frac{N}{N} = N(\frac{1}{2} + \frac{1}{3} + \frac{1}{5} + \ldots + \frac{1}{N})\]and since by harmonic number
\[\int_0^N\frac{1}{x}\,dx\ = \log{x} + c\]we can conclude that a loose upper-bound is \( O(N\log{N}) \) (a better analysis would yield \( O(N\log{\log{N}}) \)).
Interval prime generation using \( 6k\pm1 \)
If we’re prompted with the task of generating primes in a given interval \( [x;y] \) with \( x \) and \( y \) potentially large integers but close to each other (i.e. a small interval on a high-range,) a faster approach could be exploiting the \( 6k\pm1 \) property (a variation on Euclid’s proof of infinite primes). The argument shows that any prime \( P \) is either of the form \( 6k+1 \) or \( 6k-1 \).
A prime number greater than 3 cannot have the following forms:
- \( 6k \) since it would be divisible by 2 and 3
- \( 6k\pm2 \) since it would be divisible by 2
- \( 6k\pm3 \) since it would be divisible by 3
- \( 6k\pm4 \) since it would be divisible by 2
so it is either of the form \( 6k\pm1 \) or \( 6k\pm5 \). The latter form is equivalent to the first one since increasing the index \( k \) yields \( 6(k+1)-5 = 6k+1 \). The same holds for \( 6k-1 \).
Therefore if we need to generate primes into a given interval we can simply reach a \( 6k\pm1 \) number in that interval and proceed with the primality testing. Testing for a \( 6k\pm1 \) number to be a prime is a necessary check since all primes are of the form \( 6k\pm1 \) but not all \( 6k\pm1 \) numbers are prime (e.g. \( 6k-1 \) with \( k=6 \)).
The code features many optimization spots and has been kept overly verbose for readability purposes. Complexity is \( O((y-x)\sqrt{y}) \) being the primality test the most expensive operation.