Sieve of Eratosthenes (Python, arrays)

From LiteratePrograms

Jump to: navigation, search
Other implementations: Alice ML | Bash | C++ | Forth | Haskell | Java | Python | Python, arrays | Scala

The Sieve of Eratosthenes is an algorithm for rapidly locating all the prime numbers in a certain range of integers. It operates by marking as composite all nontrivial multiples of each prime in sequence until only primes remain unmarked. It is most well-suited to implementation using arrays, which are compact and feature random access.


Contents

simple implementation

We follow the algorithm outlined in the introduction.

<<sieve>>=
  initialize the sieve
  test each possible factor in sequence
          mark nontrivial multiples
  return unmarked primes

First we set up an array of n2 flags, initially all set to 1, indicating primes.

<<initialize the sieve>>=
flags = zeros(n**2) + 1

Next we take each nontrivial factor, from [2,n) ...

<<test each possible factor in sequence>>=
for i in arange(2,n):

... and mark the nontrivial multiples.

  • we start at i2 because lower multiples will have been tested earlier in the sequence
  • by using a stride of i all higher multiples are set in the same statement
<<mark nontrivial multiples>>=
flags[i*i::i] = 0

As a result, the remaining unmarked elements are 0, 1, and the primes; we drop the first two to return only the primes.

<<return unmarked primes>>=
return nonzero(flags)[2:]

more complex implementation

We can attempt to speed the algorithm up by precalculating the first few passes. With a variant of wheel factorization, rather than initializing the sieve to all ones, we replicate a pattern without multiples of 2 and 3, and then reset the flags for the trivial multiples themselves.

<<initialize precalculated sieve>>=
flags = resize((0,1,0,0,0,1), (n**2,))
put(flags, (0,2,3), 1)

Because of the precalculation, we start testing from the next remaining prime, 5. Also, instead of testing each factor, prime or composite, we check the results calculated so far to test only the prime factors.

<<test each prime factor in sequence>>=
for i in arange(5,n,2):
    if flags[i]:

The remainder of the algorithm remains unchanged.

<<koskinon>>=
  initialize precalculated sieve
  test each prime factor in sequence
          mark nontrivial multiples
  return unmarked primes

putting it all together

Finally, we generate a list of the primes less than 9'999, and check that sieve and koskinon yield identical results.

<<sieve.py>>=
from Numeric import *

def sieve(n):
sieve

def koskinon(n):
koskinon

if __name__ == "__main__":
        print sieve(100)
        print multiply.reduce(koskinon(100)==sieve(100))

which we expect to produce:

[   2    3    5    7   11   13   17   19   23   29   31   37   41   43   47
      53   59   61   67   71   73   79   83   89   97  101  103  107  109
      ...
      9781 9787 9791 9803 9811 9817 9829 9833 9839 9851 9857 9859 9871 9883
      9887 9901 9907 9923 9929 9931 9941 9949 9967 9973]
1

επίλογος

Was the extra complexity of koskinon worthwhile? On the machine tested, it appears to be less than twice as fast as sieve.


„Die ganzen Zahlen hat der liebe Gott gemacht, alles andere ist Menschenwerk.“ — L Kronecker

Download code
Personal tools