This is the best algorithm I could come up.
def get_primes(n):
numbers = set(range(n, 1, -1))
primes = []
while numbers:
p = numbers.pop()
primes.append(p)
numbers.difference_update(set(range(p*2, n+1, p)))
return primes
>>> timeit.Timer(stmt='get_primes.get_primes(1000000)', setup='import get_primes').timeit(1)
1.1499958793645562
Can it be made even faster?
This code has a flaw: Since numbers is an unordered set, there is no guarantee that numbers.pop() will remove the lowest number from the set. Nevertheless, it works (at least for me) for some input numbers:
>>> sum(get_primes(2000000))
142913828922L
#That's the correct sum of all numbers below 2 million
>>> 529 in get_primes(1000)
False
>>> 529 in get_primes(530)
True
Warning:
timeitresults may vary due to differences in hardware orversion of Python.
Below is a script which compares a number of implementations:
Many thanks to stephan for bringing sieve_wheel_30 to my attention.
Credit goes to Robert William Hanks for primesfrom2to, primesfrom3to, rwh_primes, rwh_primes1, and rwh_primes2.
Of the plain Python methods tested, with psyco, for n=1000000,
rwh_primes1 was the fastest tested.
Of the plain Python methods tested, without psyco, for n=1000000,
rwh_primes2 was the fastest.
Of all the methods tested, allowing numpy, for n=1000000,
primesfrom2to was the fastest tested.
Timings were measured using the command:
with
{method}replaced by each of the method names.primes.py:
Running the script tests that all implementations give the same result.