Last active
August 21, 2020 12:14
-
-
Save arlyon/0d90932adcb5a8a05b0bb6fa21518a04 to your computer and use it in GitHub Desktop.
A 2-cycle fast and pythonic implementation of the sieve or eratosthenes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from itertools import count | |
from collections import defaultdict | |
def eratosthenes(): | |
""" | |
Infinitely generates primes using the sieve of Eratosthenes. | |
""" | |
yield 2 | |
candidate_factorizations = defaultdict(set) | |
for candidate in count(3, 2): | |
if candidate not in candidate_factorizations: | |
yield candidate | |
candidate_factorizations[candidate ** 2].add(candidate) | |
else: | |
for prime in candidate_factorizations[candidate]: | |
candidate_factorizations[candidate + prime * 2].add(prime) | |
del candidate_factorizations[candidate] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Benchmarks:
I compared this to a naive trial division implementation as well as the fastest "classic" non-generator implementation I could find: rwh_primes2_python3.
The generator is, with the additional overhead of "rolling forward" primes, quite a bit slower than the bounded version by about a factor of 20 but still looks linear from my calculations. Not bad considering the overhead required to generate infinitely and comparing the general legibility of the code!
With 10,000 primes:
10 loops, best of 3: 4.65 sec per loop
10 loops, best of 3: 39.7 msec per loop
1000 loops, best of 3: 1.95 msec per loop
Removing the trial division allows us to up the numbers a little and compare 1,000,000 primes:
10 loops, best of 3: 7.3 sec per loop
10 loops, best of 3: 285 msec per loop