Computes an infinite sequence of primes using simple generators. A Python dictionary is used to mark multiples of the generated primes, according to the Sieve of Eratosthenes.
| Python |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # Sieve of Eratosthenes
# David Eppstein, UC Irvine, 28 Feb 2002
from __future__ import generators
def eratosthenes():
'''Yields the sequence of prime numbers via the Sieve of Eratosthenes.'''
D = {} # map composite integers to primes witnessing their compositeness
q = 2 # first integer to test for primality
while 1:
if q not in D:
yield q # not marked composite, must be prime
D[q*q] = [q] # first multiple of q not already marked
else:
for p in D[q]: # move each witness to its next multiple
D.setdefault(p+q,[]).append(p)
del D[q] # no longer need D[q], free memory
q += 1
|
Discussion
As Wim Stolker suggested, I have modified this to use setdefault, 1 Mar 2001.


Comments
Shortcut. Nice short and clear recipe, however,
Instead of:
I would use:
See: Add an entry to a dictionary, unless the entry is already there.
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66516
slightly faster by keeping a dict of single numbers instead of one of lists. neat indeed, but we can be marginally faster (about 40%+ on my machine for primes up to 1,000,000 for example) by keeping in the dict a single value for each composite number -- the first prime factor that revealed to us that number is a composite. Here's the Python 2.3 code for the enhanced main loop:
this uses the new-in-2.3 "fetch and remove" method .pop of dictionaries, but that's marginal (and I put just the same small enhancement in the list-using version -- I posted both to comp.lang.python just now) -- the small speedup in this variant comes from not having to build so many small lists.
Alex
I hapen to like haskell's. haskell's canonical version:
translates roughly to python as:
Unfortunately it exceeds the recursion limit after about 3000 on my machine.
Slightly faster yet by skipping even numbers.
It's too bad itertools.count doesn't take a step argument! This would look cleaner, and likely be marginally faster, with
rather than the current while True cruft.
Another recursive version.
This uses ifilter to generate the recursive sequence. It's much less vulnerable to stack overflow than the version that recurses on sieve, but otherwise it's pretty similar.
I managed to generate all primes up to 909,691 before it bombed the Python interpreter mysteriously, but it takes a while!
Sign in to comment