Reputation: 29634
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
Upvotes: 402
Views: 288875
Reputation: 7204
A very fast 1.9s< implementation using numba! I think for 100 million numbers this is the fastest! This is based on an idea I had for primes on a post long ago
import numpy
from numba import njit, prange
@njit(parallel=True)
def parallel_sieve(limit):
sieve_size = (limit // 2) + 1
sieve_array = np.ones(sieve_size, dtype=np.bool_)
sieve_array[0] = False
for i in prange(1, int(limit ** 0.5) // 2 + 1):
if sieve_array[i]:
p = 2 * i + 1
start_index = (p * p) // 2
sieve_array[start_index::p] = False
primes = [2]
for i in range(1, sieve_size):
if sieve_array[i]:
primes.append(2 * i + 1)
return np.array(primes)
limit = 1_000_000_000 #1 billion
a = parallel_sieve(limit)
%timeit parallel_sieve(limit)
# 3.77 s ± 543 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [13]: len(a)
Out[13]: 50847534
Upvotes: 0
Reputation: 2339
at this point of time, fermet method
may be the fastest way
of matching prime numbers
. but there are cases when fermet may go wrong (carmichael numbers
). in such cases you may wish to use the square root primes check method
to do a recheck of whether it is prime or not.
i have not seen any person use this way of calculation at this time. well, say till july 2024, strange?
https://en.wikipedia.org/wiki/Fermat_number
https://en.wikipedia.org/wiki/Primality_test
# Fermet way of checking primes with base 2
# you can change the 2 into any other coprime number
def isPrimeFermet(num):
if (num < 2): return False;
if (num == 2 or num == 3 or num == 5 or num == 7 or num == 11): return True
if (2**(num - 1) % num == 1): return True;
return False;
#
# optimised uses checks of primes for until 11 and its multiplicals
# before using the use of fermet method
#
# this check reduces the possibilities of carmichael numbers which are
# derivatived from coprimes of 2,3,5,7,11
#
# you may add more of prime numbers to the checks to
# better the possibility until 100 or more stored primes
# the function will have better probability to not
# get any carmichael nonprime number
#
def isPrimeFermetOptimized(num):
if (num < 2): return False;
if (num == 2 or num == 3 or num == 5 or num == 7 or num == 11):
return True
if ( (num == 1) or ( (num > 11) and ( ((num % 2) == 0) or ((num % 3) == 0) or ((num % 5) == 0) or ((num % 7) == 0) ) ) ):
return False
if (2**(num - 1) % num == 1): return True;
return False;
get prime numbers between one
(or alternatively start
) to
range
of until r
using the function isPrimeFermetRange(range)
or isPrimeFermetRange(start, range)
def isPrimeFermetRange(r):
primes = [2];
for i in range(1, r):
if (isPrimeFermet(i)):
primes.append(i);
return primes;
def isPrimeFermetRange(s, r):
primes = [];
for i in range(s, r):
if (isPrimeFermet(i)):
primes.append(i);
return primes;
a confirmation for carmichael numbers can be done using the square root methods of checking primes.
# if you are unsure whether it is a carmical number, then
# you may use the square root method to
# recheck and confirm the number to be a prime or carmical
def isPrimeSquareRoot(num):
count = 0
if (num < 2): return False;
s = math.sqrt(num)
s = int(s+1)
for i in range(2, s):
count += 1
if (num % i == 0):
return False
return True
#
# optimised uses checks of primes for until 11 and its multiplicals
# before using the use of fermet method
#
# this check reduces the possibilities of carmichael numbers which are
# derivatived from coprimes of 2,3,5,7,11
#
# you may add more of prime numbers to the checks to
# better the possibility until 100 or more stored primes
# the function will have better probability to not
# get any carmichael nonprime number
#
def isPrimeSquareRootOptimised(num):
count = 0
if (num < 2): return False;
if (num == 2 or num == 3 or num == 5 or num == 7 or num == 11):
return True
if ( (num == 1) or ( (num > 11) and ( ((num % 2) == 0) or ((num % 3) == 0) or ((num % 5) == 0) or ((num % 7) == 0) ) ) ):
return False
s = math.sqrt(num)
s = int(s+1)
for i in range(2, s):
count += 1
if (num % i == 0):
return False
return True
Upvotes: 0
Reputation: 189
I have a faster sieve_of_eratosthenes(n) It is still slower than primesfrom2to(n) but is faster than the original sieve of Eratosthenes. It is a bit slower than from2 because it does not compress the primes list by 3.
def sieve_of_eratosthenes(n):
"""Create a sieve of Eratosthenes up to the given size."""
p =np.ones(n,dtype=bool) # One byte per value
p[0:2] = False # Clear zero and one
p[4::2] = False # Clear multiples of 2
p[9::3] = False # Clear multiples of 3
for i in range(5,isqrt(n)+1,6): # Process only numbers of the form 6k-1 and 6k+1
if p[i]: # If 6k-1 is prime
p[i*i::2*i] = False # Clear multiples of 6k-1
h = i + 2 # 6k+1
if p[h]: # If 6k+1 is prime
p[h*h::2*h] = False # Clear multiples of 6k+1
#return p
return np.r_[np.flatnonzero(p)]
Output looks like this against primesfrom2to(n):
Primes from 2 to ..
100: 25 time: 0.0001073
1,000: 168 time: 0.0002327
10,000: 1,229 time: 0.0003760
100,000: 9,592 time: 0.0007730
1,000,000: 78,498 time: 0.0033276
10,000,000: 664,579 time: 0.0242670
100,000,000: 5,761,455 time: 0.3516040
1,000,000,000: 50,847,534 time: 4.2745979
Primes bitarray sieve ..
100: 25 time: 0.0011809
1,000: 168 time: 0.0012677
10,000: 1,229 time: 0.0013816
100,000: 9,592 time: 0.0017211
1,000,000: 78,498 time: 0.0042264
10,000,000: 664,579 time: 0.0379338
100,000,000: 5,761,455 time: 0.5743241
1,000,000,000: 50,847,534 time: 6.5816255
Upvotes: 0
Reputation: 2805
You can save a lot of space by first pre-filtering down all 8 scenarios of the mod 30 wheel
collapsed down to this simple formula :
((x % 30) - 15)^4 % 30 == 16
or simply
( x % 30 - 15 )^4 % 30 == 16
Then each byte can represent exactly 1 spin of the wheel, which is already 73.3% space savings right off the bat compared to 1 bit for every natural number.
(I usually prefer starting the wheel at 11,13,...,31,37
instead of 1,7,...,23,29
)
Upvotes: 0
Reputation: 6905
A deterministic implementation of Miller-Rabin's Primality test on the assumption that N < 9,080,191
import sys
def miller_rabin_pass(a, n):
d = n - 1
s = 0
while d % 2 == 0:
d >>= 1
s += 1
a_to_power = pow(a, d, n)
if a_to_power == 1:
return True
for i in range(s-1):
if a_to_power == n - 1:
return True
a_to_power = (a_to_power * a_to_power) % n
return a_to_power == n - 1
def miller_rabin(n):
if n <= 2:
return n == 2
if n < 2_047:
return miller_rabin_pass(2, n)
return all(miller_rabin_pass(a, n) for a in (31, 73))
n = int(sys.argv[1])
primes = [2]
for p in range(3,n,2):
if miller_rabin(p):
primes.append(p)
print len(primes)
According to the article on Wikipedia (http://en.wikipedia.org/wiki/Miller–Rabin_primality_test) testing N < 9,080,191 for a = 31 and 73 is enough to decide whether N is composite or not.
And I adapted the source code from the probabilistic implementation of original Miller-Rabin's test found here: https://www.literateprograms.org/miller-rabin_primality_test__python_.html
Upvotes: 4
Reputation: 29
def find_primes(n):
# Create a boolean list to track prime numbers
primes = [True] * (n+1)
primes[0] = primes[1] = False
# Mark all multiples of 2 as composite (except 2 itself)
for i in range(4, n+1, 2):
primes[i] = False
# Iterate over all odd numbers and mark their multiples as composite
for i in range(3, int(n**0.5)+1, 2):
if primes[i]:
for j in range(i*i, n+1, 2*i):
primes[j] = False
# Return a list of prime numbers
return [i for i in range(n+1) if primes[I]]
primes = find_primes(1000000)
print(primes)
The find_primes function takes an integer n as input and returns a list of all prime numbers from 1 to n. The code first creates a boolean list primes of length n+1 to track prime numbers. It then marks all multiples of 2 as composite (except 2 itself), since all other even numbers are not prime. Next, it iterates over all odd numbers from 3 to the square root of n and marks their multiples as composite. Finally, it returns a list of all prime numbers by filtering out the composite numbers from the boolean list.
Note that the Sieve of Eratosthenes algorithm has a time complexity of O(n log log n), which makes it much more efficient than testing each number for primality individually.
Upvotes: 0
Reputation: 2533
I may have been slow to join the party, but I make up for it with the fastest code (at least it is on my machine, as of writing). This approach uses both numpy and bitarray, and is inspired by primesfrom2to
from this answer.
import numpy as np
from bitarray import bitarray
def bit_primes(n):
bit_sieve = bitarray(n // 3 + (n % 6 == 2))
bit_sieve.setall(1)
bit_sieve[0] = False
for i in range(int(n ** 0.5) // 3 + 1):
if bit_sieve[i]:
k = 3 * i + 1 | 1
bit_sieve[k * k // 3::2 * k] = False
bit_sieve[(k * k + 4 * k - 2 * k * (i & 1)) // 3::2 * k] = False
np_sieve = np.unpackbits(np.frombuffer(bit_sieve.tobytes(), dtype=np.uint8)).view(bool)
return np.concatenate(((2, 3), ((3 * np.flatnonzero(np_sieve) + 1) | 1)))
Here's a comparison with primesfrom2to
, which was previously found to be the fastest solution in unutbu's comparison:
python3 -m timeit -s "import fast_primes" "fast_primes.bit_primes(1000000)"
200 loops, best of 5: 1.19 msec per loop
python3 -m timeit -s "import fast_primes" "fast_primes.primesfrom2to(1000000)"
200 loops, best of 5: 1.23 msec per loop
For finding primes under 1 million, bit_primes
was slightly faster.
For larger values of n
, the difference can be more significant. In some cases, bit_primes
was over twice as fast:
python3 -m timeit -s "import fast_primes" "fast_primes.bit_primes(500_000_000)"
1 loop, best of 5: 540 msec per loop
python3 -m timeit -s "import fast_primes" "fast_primes.primesfrom2to(500_000_000)"
1 loop, best of 5: 1.15 sec per loop
For reference, here's the minimally modified (to work in Python 3) version of primesfrom2to
I compared with:
def primesfrom2to(n):
# https://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188
""" Input n>=6, Returns a array of primes, 2 <= p < n"""
sieve = np.ones(n // 3 + (n % 6 == 2), dtype=np.bool)
sieve[0] = False
for i in range(int(n ** 0.5) // 3 + 1):
if sieve[i]:
k = 3 * i + 1 | 1
sieve[((k * k) // 3)::2 * k] = False
sieve[(k * k + 4 * k - 2 * k * (i & 1)) // 3::2 * k] = False
return np.r_[2, 3, ((3 * np.nonzero(sieve)[0] + 1) | 1)]
Upvotes: 3
Reputation: 26211
I'm surprised nobody mentioned numba
yet.
This version gets to the 1M mark in 2.47 ms ± 36.5 µs.
Years ago, pseudo-code for a version of Atkin's sieve was given on the Wikipedia page Prime number. This isn't there anymore, and a reference to the Sieve of Atkin seems to be a different algorithm. A 2007/03/01 version of the Wikipedia page, Primer number as of 2007-03-01, shows the pseudo-code I used as reference.
import numpy as np
from numba import njit
@njit
def nb_primes(n):
# Generates prime numbers 2 <= p <= n
# Atkin's sieve -- see https://en.wikipedia.org/w/index.php?title=Prime_number&oldid=111775466
sqrt_n = int(np.sqrt(n)) + 1
# initialize the sieve
s = np.full(n + 1, -1, dtype=np.int8)
s[2] = 1
s[3] = 1
# put in candidate primes:
# integers which have an odd number of
# representations by certain quadratic forms
for x in range(1, sqrt_n):
x2 = x * x
for y in range(1, sqrt_n):
y2 = y * y
k = 4 * x2 + y2
if k <= n and (k % 12 == 1 or k % 12 == 5): s[k] *= -1
k = 3 * x2 + y2
if k <= n and (k % 12 == 7): s[k] *= -1
k = 3 * x2 - y2
if k <= n and x > y and k % 12 == 11: s[k] *= -1
# eliminate composites by sieving
for k in range(5, sqrt_n):
if s[k]:
k2 = k*k
# k is prime, omit multiples of its square; this is sufficient because
# composites which managed to get on the list cannot be square-free
for i in range(1, n // k2 + 1):
j = i * k2 # j ∈ {k², 2k², 3k², ..., n}
s[j] = -1
return np.nonzero(s>0)[0]
# initial run for "compilation"
nb_primes(10)
In[10]:
%timeit nb_primes(1_000_000)
Out[10]:
2.47 ms ± 36.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In[11]:
%timeit nb_primes(10_000_000)
Out[11]:
33.4 ms ± 373 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
In[12]:
%timeit nb_primes(100_000_000)
Out[12]:
828 ms ± 5.64 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
Upvotes: 3
Reputation: 3613
Starting from this 2021 answer, I haven't found bitarray
approach to be beneficial for primes below 1 billion.
But I was able to speedup primesfrom2to
almost x2 with several tricks:
numexpr
library to convert numpy expressions to tight loops with less allocationsnp.ones
with a faster alternativeAll in all, time for primes <1 billion went from 25s to 14.5s on my machine
import numexpr as ne
import numpy as np
def primesfrom2to_numexpr(n):
# https://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188
""" Input n>=24, Returns a array of primes, 2 <= p < n + a few over"""
sieve = np.zeros((n // 3 + (n % 6 == 2))//4+1, dtype=np.int32)
ne.evaluate('sieve + 0x01010101', out=sieve)
sieve = sieve.view('int8')
#sieve = np.ones(n // 3 + (n % 6 == 2), dtype=np.bool_)
sieve[0] = 0
for i in np.arange(int(n ** 0.5) // 3 + 1):
if sieve[i]:
k = 3 * i + 1 | 1
sieve[((k * k) // 3)::2 * k] = 0
sieve[(k * k + 4 * k - 2 * k * (i & 1)) // 3::2 * k] = 0
sieve[[0,8]] = 1
result = np.flatnonzero(sieve)
ne.evaluate('result * 3 + 1 + result%2', out=result)
result[:9] = [2,3,5,7,11,13,17,19,23]
return result
Upvotes: 1
Reputation: 58791
I've updated much of the code for Python 3 and threw it at perfplot (a project of mine) to see which is actually fastest. Turns out that, for large n
, primesfrom{2,3}to
takes the cake:
Code to reproduce the plot:
import perfplot
from math import sqrt, ceil
import numpy as np
import sympy
def rwh_primes(n):
# https://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188
""" Returns a list of primes < n """
sieve = [True] * n
for i in range(3, int(n ** 0.5) + 1, 2):
if sieve[i]:
sieve[i * i::2 * i] = [False] * ((n - i * i - 1) // (2 * i) + 1)
return [2] + [i for i in range(3, n, 2) if sieve[i]]
def rwh_primes1(n):
# https://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188
""" Returns a list of primes < n """
sieve = [True] * (n // 2)
for i in range(3, int(n ** 0.5) + 1, 2):
if sieve[i // 2]:
sieve[i * i // 2::i] = [False] * ((n - i * i - 1) // (2 * i) + 1)
return [2] + [2 * i + 1 for i in range(1, n // 2) if sieve[i]]
def rwh_primes2(n):
# https://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188
"""Input n>=6, Returns a list of primes, 2 <= p < n"""
assert n >= 6
correction = n % 6 > 1
n = {0: n, 1: n - 1, 2: n + 4, 3: n + 3, 4: n + 2, 5: n + 1}[n % 6]
sieve = [True] * (n // 3)
sieve[0] = False
for i in range(int(n ** 0.5) // 3 + 1):
if sieve[i]:
k = 3 * i + 1 | 1
sieve[((k * k) // 3)::2 * k] = [False] * (
(n // 6 - (k * k) // 6 - 1) // k + 1
)
sieve[(k * k + 4 * k - 2 * k * (i & 1)) // 3::2 * k] = [False] * (
(n // 6 - (k * k + 4 * k - 2 * k * (i & 1)) // 6 - 1) // k + 1
)
return [2, 3] + [3 * i + 1 | 1 for i in range(1, n // 3 - correction) if sieve[i]]
def sieve_wheel_30(N):
# http://zerovolt.com/?p=88
""" Returns a list of primes <= N using wheel criterion 2*3*5 = 30
Copyright 2009 by zerovolt.com
This code is free for non-commercial purposes, in which case you can just leave this comment as a credit for my work.
If you need this code for commercial purposes, please contact me by sending an email to: info [at] zerovolt [dot] com."""
__smallp = (
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,
113,
127,
131,
137,
139,
149,
151,
157,
163,
167,
173,
179,
181,
191,
193,
197,
199,
211,
223,
227,
229,
233,
239,
241,
251,
257,
263,
269,
271,
277,
281,
283,
293,
307,
311,
313,
317,
331,
337,
347,
349,
353,
359,
367,
373,
379,
383,
389,
397,
401,
409,
419,
421,
431,
433,
439,
443,
449,
457,
461,
463,
467,
479,
487,
491,
499,
503,
509,
521,
523,
541,
547,
557,
563,
569,
571,
577,
587,
593,
599,
601,
607,
613,
617,
619,
631,
641,
643,
647,
653,
659,
661,
673,
677,
683,
691,
701,
709,
719,
727,
733,
739,
743,
751,
757,
761,
769,
773,
787,
797,
809,
811,
821,
823,
827,
829,
839,
853,
857,
859,
863,
877,
881,
883,
887,
907,
911,
919,
929,
937,
941,
947,
953,
967,
971,
977,
983,
991,
997,
)
# wheel = (2, 3, 5)
const = 30
if N < 2:
return []
if N <= const:
pos = 0
while __smallp[pos] <= N:
pos += 1
return list(__smallp[:pos])
# make the offsets list
offsets = (7, 11, 13, 17, 19, 23, 29, 1)
# prepare the list
p = [2, 3, 5]
dim = 2 + N // const
tk1 = [True] * dim
tk7 = [True] * dim
tk11 = [True] * dim
tk13 = [True] * dim
tk17 = [True] * dim
tk19 = [True] * dim
tk23 = [True] * dim
tk29 = [True] * dim
tk1[0] = False
# help dictionary d
# d[a , b] = c ==> if I want to find the smallest useful multiple of (30*pos)+a
# on tkc, then I need the index given by the product of [(30*pos)+a][(30*pos)+b]
# in general. If b < a, I need [(30*pos)+a][(30*(pos+1))+b]
d = {}
for x in offsets:
for y in offsets:
res = (x * y) % const
if res in offsets:
d[(x, res)] = y
# another help dictionary: gives tkx calling tmptk[x]
tmptk = {1: tk1, 7: tk7, 11: tk11, 13: tk13, 17: tk17, 19: tk19, 23: tk23, 29: tk29}
pos, prime, lastadded, stop = 0, 0, 0, int(ceil(sqrt(N)))
# inner functions definition
def del_mult(tk, start, step):
for k in range(start, len(tk), step):
tk[k] = False
# end of inner functions definition
cpos = const * pos
while prime < stop:
# 30k + 7
if tk7[pos]:
prime = cpos + 7
p.append(prime)
lastadded = 7
for off in offsets:
tmp = d[(7, off)]
start = (
(pos + prime)
if off == 7
else (prime * (const * (pos + 1 if tmp < 7 else 0) + tmp)) // const
)
del_mult(tmptk[off], start, prime)
# 30k + 11
if tk11[pos]:
prime = cpos + 11
p.append(prime)
lastadded = 11
for off in offsets:
tmp = d[(11, off)]
start = (
(pos + prime)
if off == 11
else (prime * (const * (pos + 1 if tmp < 11 else 0) + tmp)) // const
)
del_mult(tmptk[off], start, prime)
# 30k + 13
if tk13[pos]:
prime = cpos + 13
p.append(prime)
lastadded = 13
for off in offsets:
tmp = d[(13, off)]
start = (
(pos + prime)
if off == 13
else (prime * (const * (pos + 1 if tmp < 13 else 0) + tmp)) // const
)
del_mult(tmptk[off], start, prime)
# 30k + 17
if tk17[pos]:
prime = cpos + 17
p.append(prime)
lastadded = 17
for off in offsets:
tmp = d[(17, off)]
start = (
(pos + prime)
if off == 17
else (prime * (const * (pos + 1 if tmp < 17 else 0) + tmp)) // const
)
del_mult(tmptk[off], start, prime)
# 30k + 19
if tk19[pos]:
prime = cpos + 19
p.append(prime)
lastadded = 19
for off in offsets:
tmp = d[(19, off)]
start = (
(pos + prime)
if off == 19
else (prime * (const * (pos + 1 if tmp < 19 else 0) + tmp)) // const
)
del_mult(tmptk[off], start, prime)
# 30k + 23
if tk23[pos]:
prime = cpos + 23
p.append(prime)
lastadded = 23
for off in offsets:
tmp = d[(23, off)]
start = (
(pos + prime)
if off == 23
else (prime * (const * (pos + 1 if tmp < 23 else 0) + tmp)) // const
)
del_mult(tmptk[off], start, prime)
# 30k + 29
if tk29[pos]:
prime = cpos + 29
p.append(prime)
lastadded = 29
for off in offsets:
tmp = d[(29, off)]
start = (
(pos + prime)
if off == 29
else (prime * (const * (pos + 1 if tmp < 29 else 0) + tmp)) // const
)
del_mult(tmptk[off], start, prime)
# now we go back to top tk1, so we need to increase pos by 1
pos += 1
cpos = const * pos
# 30k + 1
if tk1[pos]:
prime = cpos + 1
p.append(prime)
lastadded = 1
for off in offsets:
tmp = d[(1, off)]
start = (
(pos + prime)
if off == 1
else (prime * (const * pos + tmp)) // const
)
del_mult(tmptk[off], start, prime)
# time to add remaining primes
# if lastadded == 1, remove last element and start adding them from tk1
# this way we don't need an "if" within the last while
if lastadded == 1:
p.pop()
# now complete for every other possible prime
while pos < len(tk1):
cpos = const * pos
if tk1[pos]:
p.append(cpos + 1)
if tk7[pos]:
p.append(cpos + 7)
if tk11[pos]:
p.append(cpos + 11)
if tk13[pos]:
p.append(cpos + 13)
if tk17[pos]:
p.append(cpos + 17)
if tk19[pos]:
p.append(cpos + 19)
if tk23[pos]:
p.append(cpos + 23)
if tk29[pos]:
p.append(cpos + 29)
pos += 1
# remove exceeding if present
pos = len(p) - 1
while p[pos] > N:
pos -= 1
if pos < len(p) - 1:
del p[pos + 1 :]
# return p list
return p
def sieve_of_eratosthenes(n):
"""sieveOfEratosthenes(n): return the list of the primes < n."""
# Code from: <[email protected]>, Nov 30 2006
# http://groups.google.com/group/comp.lang.python/msg/f1f10ced88c68c2d
if n <= 2:
return []
sieve = list(range(3, n, 2))
top = len(sieve)
for si in sieve:
if si:
bottom = (si * si - 3) // 2
if bottom >= top:
break
sieve[bottom::si] = [0] * -((bottom - top) // si)
return [2] + [el for el in sieve if el]
def sieve_of_atkin(end):
"""return a list of all the prime numbers <end using the Sieve of Atkin."""
# Code by Steve Krenzel, <[email protected]>, improved
# Code: https://web.archive.org/web/20080324064651/http://krenzel.info/?p=83
# Info: http://en.wikipedia.org/wiki/Sieve_of_Atkin
assert end > 0
lng = (end - 1) // 2
sieve = [False] * (lng + 1)
x_max, x2, xd = int(sqrt((end - 1) / 4.0)), 0, 4
for xd in range(4, 8 * x_max + 2, 8):
x2 += xd
y_max = int(sqrt(end - x2))
n, n_diff = x2 + y_max * y_max, (y_max << 1) - 1
if not (n & 1):
n -= n_diff
n_diff -= 2
for d in range((n_diff - 1) << 1, -1, -8):
m = n % 12
if m == 1 or m == 5:
m = n >> 1
sieve[m] = not sieve[m]
n -= d
x_max, x2, xd = int(sqrt((end - 1) / 3.0)), 0, 3
for xd in range(3, 6 * x_max + 2, 6):
x2 += xd
y_max = int(sqrt(end - x2))
n, n_diff = x2 + y_max * y_max, (y_max << 1) - 1
if not (n & 1):
n -= n_diff
n_diff -= 2
for d in range((n_diff - 1) << 1, -1, -8):
if n % 12 == 7:
m = n >> 1
sieve[m] = not sieve[m]
n -= d
x_max, y_min, x2, xd = int((2 + sqrt(4 - 8 * (1 - end))) / 4), -1, 0, 3
for x in range(1, x_max + 1):
x2 += xd
xd += 6
if x2 >= end:
y_min = (((int(ceil(sqrt(x2 - end))) - 1) << 1) - 2) << 1
n, n_diff = ((x * x + x) << 1) - 1, (((x - 1) << 1) - 2) << 1
for d in range(n_diff, y_min, -8):
if n % 12 == 11:
m = n >> 1
sieve[m] = not sieve[m]
n += d
primes = [2, 3]
if end <= 3:
return primes[: max(0, end - 2)]
for n in range(5 >> 1, (int(sqrt(end)) + 1) >> 1):
if sieve[n]:
primes.append((n << 1) + 1)
aux = (n << 1) + 1
aux *= aux
for k in range(aux, end, 2 * aux):
sieve[k >> 1] = False
s = int(sqrt(end)) + 1
if s % 2 == 0:
s += 1
primes.extend([i for i in range(s, end, 2) if sieve[i >> 1]])
return primes
def ambi_sieve_plain(n):
s = list(range(3, n, 2))
for m in range(3, int(n ** 0.5) + 1, 2):
if s[(m - 3) // 2]:
for t in range((m * m - 3) // 2, (n >> 1) - 1, m):
s[t] = 0
return [2] + [t for t in s if t > 0]
def sundaram3(max_n):
# https://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python/2073279#2073279
numbers = range(3, max_n + 1, 2)
half = (max_n) // 2
initial = 4
for step in range(3, max_n + 1, 2):
for i in range(initial, half, step):
numbers[i - 1] = 0
initial += 2 * (step + 1)
if initial > half:
return [2] + filter(None, numbers)
# Using Numpy:
def ambi_sieve(n):
# http://tommih.blogspot.com/2009/04/fast-prime-number-generator.html
s = np.arange(3, n, 2)
for m in range(3, int(n ** 0.5) + 1, 2):
if s[(m - 3) // 2]:
s[(m * m - 3) // 2::m] = 0
return np.r_[2, s[s > 0]]
def primesfrom3to(n):
# https://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188
""" Returns an array of primes, p < n """
assert n >= 2
sieve = np.ones(n // 2, dtype=bool)
for i in range(3, int(n ** 0.5) + 1, 2):
if sieve[i // 2]:
sieve[i * i // 2::i] = False
return np.r_[2, 2 * np.nonzero(sieve)[0][1::] + 1]
def primesfrom2to(n):
# https://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188
""" Input n>=6, Returns an array of primes, 2 <= p < n """
assert n >= 6
sieve = np.ones(n // 3 + (n % 6 == 2), dtype=bool)
sieve[0] = False
for i in range(int(n ** 0.5) // 3 + 1):
if sieve[i]:
k = 3 * i + 1 | 1
sieve[((k * k) // 3)::2 * k] = False
sieve[(k * k + 4 * k - 2 * k * (i & 1)) // 3::2 * k] = False
return np.r_[2, 3, ((3 * np.nonzero(sieve)[0] + 1) | 1)]
def sympy_sieve(n):
return list(sympy.sieve.primerange(1, n))
b = perfplot.bench(
setup=lambda n: n,
kernels=[
rwh_primes,
rwh_primes1,
rwh_primes2,
sieve_wheel_30,
sieve_of_eratosthenes,
sieve_of_atkin,
# ambi_sieve_plain,
# sundaram3,
ambi_sieve,
primesfrom3to,
primesfrom2to,
sympy_sieve,
],
n_range=[2 ** k for k in range(3, 25)],
xlabel="n",
)
b.save("out.png")
b.show()
Upvotes: 9
Reputation: 361
Faster & more memory-wise pure Python code:
def primes(n):
""" Returns a list of primes < n """
sieve = [True] * n
for i in range(3,int(n**0.5)+1,2):
if sieve[i]:
sieve[i*i::2*i]=[False]*((n-i*i-1)//(2*i)+1)
return [2] + [i for i in range(3,n,2) if sieve[i]]
or starting with half sieve
def primes1(n):
""" Returns a list of primes < n """
sieve = [True] * (n//2)
for i in range(3,int(n**0.5)+1,2):
if sieve[i//2]:
sieve[i*i//2::i] = [False] * ((n-i*i-1)//(2*i)+1)
return [2] + [2*i+1 for i in range(1,n//2) if sieve[i]]
Faster & more memory-wise numpy code:
import numpy
def primesfrom3to(n):
""" Returns a array of primes, 3 <= p < n """
sieve = numpy.ones(n//2, dtype=bool)
for i in range(3,int(n**0.5)+1,2):
if sieve[i//2]:
sieve[i*i//2::i] = False
return 2*numpy.nonzero(sieve)[0][1::]+1
a faster variation starting with a third of a sieve:
import numpy
def primesfrom2to(n):
""" Input n>=6, Returns a array of primes, 2 <= p < n """
sieve = numpy.ones(n//3 + (n%6==2), dtype=bool)
for i in range(1,int(n**0.5)//3+1):
if sieve[i]:
k=3*i+1|1
sieve[ k*k//3 ::2*k] = False
sieve[k*(k-2*(i&1)+4)//3::2*k] = False
return numpy.r_[2,3,((3*numpy.nonzero(sieve)[0][1:]+1)|1)]
A (hard-to-code) pure-python version of the above code would be:
def primes2(n):
""" Input n>=6, Returns a list of primes, 2 <= p < n """
n, correction = n-n%6+6, 2-(n%6>1)
sieve = [True] * (n//3)
for i in range(1,int(n**0.5)//3+1):
if sieve[i]:
k=3*i+1|1
sieve[ k*k//3 ::2*k] = [False] * ((n//6-k*k//6-1)//k+1)
sieve[k*(k-2*(i&1)+4)//3::2*k] = [False] * ((n//6-k*(k-2*(i&1)+4)//6-1)//k+1)
return [2,3] + [3*i+1|1 for i in range(1,n//3-correction) if sieve[i]]
Unfortunately pure-python don't adopt the simpler and faster numpy way of doing assignment, and calling len()
inside the loop as in [False]*len(sieve[((k*k)//3)::2*k])
is too slow. So I had to improvise to correct input (& avoid more math) and do some extreme (& painful) math-magic.
Personally I think it is a shame that numpy (which is so widely used) is not part of Python standard library, and that the improvements in syntax and speed seem to be completely overlooked by Python developers.
Upvotes: 163
Reputation:
You have a faster code and also the simplest code generating primes.
but for the higher number, it's not working for n=10000, 10000000
it failed maybe it's .pop()
method
Consider: is N prime?
case 1:
You got some factors of N,
for i in range(2, N):
If N is prime loop is performed for ~(N-2) times. else less number of times
case 2:
for i in range(2, int(math.sqrt(N)):
Loop is performed for almost ~(sqrt(N)-2) times if N is prime else will break somewhere
case 3:
Better We Divide N With Only number of primes<=sqrt(N)
Where loop is performed for only π(sqrt(N)) times
π(sqrt(N)) << sqrt(N) as N increases
from math import sqrt
from time import *
prime_list = [2]
n = int(input())
s = time()
for n0 in range(2,n+1):
for i0 in prime_list:
if n0%i0==0:
break
elif i0>=int(sqrt(n0)):
prime_list.append(n0)
break
e = time()
print(e-s)
#print(prime_list); print(f'pi({n})={len(prime_list)}')
print(f'{n}: {len(prime_list)}, time: {e-s}')
Output
100: 25, time: 0.00010275840759277344
1000: 168, time: 0.0008606910705566406
10000: 1229, time: 0.015588521957397461
100000: 9592, time: 0.023436546325683594
1000000: 78498, time: 4.1965954303741455
10000000: 664579, time: 109.24591708183289
100000000: 5761455, time: 2289.130858898163
For less than 1000 seems slow but then for <10^6 I think it's faster.
Though, I couldn't understand the time complexity.
Upvotes: 0
Reputation: 7832
Here is an interesting technique to generate prime numbers (yet not the most efficient) using python's list comprehensions:
noprimes = [j for i in range(2, 8) for j in range(i*2, 50, i)]
primes = [x for x in range(2, 50) if x not in noprimes]
Upvotes: 1
Reputation: 63302
This is a variation of the solution in the question that should be faster than what's in the question. It uses a static sieve of Eratosthenes with no other optimizations.
from typing import List
def list_primes(limit: int) -> List[int]:
primes = set(range(2, limit + 1))
for i in range(2, limit + 1):
if i in primes:
primes.difference_update(set(list(range(i, limit + 1, i))[1:]))
return sorted(primes)
>>> list_primes(100)
[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]
Upvotes: 0
Reputation: 146
I found a pure Python 2 prime generator here , in a comment by Willy Good, that is faster than rwh2_primes.
def primes235(limit):
yield 2; yield 3; yield 5
if limit < 7: return
modPrms = [7,11,13,17,19,23,29,31]
gaps = [4,2,4,2,4,6,2,6,4,2,4,2,4,6,2,6] # 2 loops for overflow
ndxs = [0,0,0,0,1,1,2,2,2,2,3,3,4,4,4,4,5,5,5,5,5,5,6,6,7,7,7,7,7,7]
lmtbf = (limit + 23) // 30 * 8 - 1 # integral number of wheels rounded up
lmtsqrt = (int(limit ** 0.5) - 7)
lmtsqrt = lmtsqrt // 30 * 8 + ndxs[lmtsqrt % 30] # round down on the wheel
buf = [True] * (lmtbf + 1)
for i in xrange(lmtsqrt + 1):
if buf[i]:
ci = i & 7; p = 30 * (i >> 3) + modPrms[ci]
s = p * p - 7; p8 = p << 3
for j in range(8):
c = s // 30 * 8 + ndxs[s % 30]
buf[c::p8] = [False] * ((lmtbf - c) // p8 + 1)
s += p * gaps[ci]; ci += 1
for i in xrange(lmtbf - 6 + (ndxs[(limit - 7) % 30])): # adjust for extras
if buf[i]: yield (30 * (i >> 3) + modPrms[i & 7])
My results:
$ time ./prime_rwh2.py 1e8
5761455 primes found < 1e8
real 0m3.201s
user 0m2.609s
sys 0m0.578s
$ time ./prime_wheel.py 1e8
5761455 primes found < 1e8
real 0m2.710s
user 0m2.469s
sys 0m0.219s
...on my recent midrange laptop (i5 8265U 1.6GHz) running Ubuntu on Win 10.
This is a mod 30 wheel sieve which skips multiples of 2, 3, and 5. It works great for me up to about 2.5e9, when my laptop starts running out of 8G RAM and swapping a lot.
I like mod 30 since it has only 8 remainders that aren't multiples of 2, 3, or 5. That enables using shifts and "&" for multiplication, division and mod, and should allow packing results for one mod 30 wheel into a byte. I have morphed Willy's code into a segmented mod 30 wheel sieve to eliminate the thrashing for big N and posted it here.
There is an even faster Javascript version which is segmented and uses a mod 210 wheel (no multiples of 2, 3, 5, or 7) by @GordonBGood with an in depth explanation that is useful to me.
Upvotes: 0
Reputation: 48759
The simplest way I've found of doing this is:
primes = []
for n in range(low, high + 1):
if all(n % i for i in primes):
primes.append(n)
Upvotes: 3
Reputation: 1931
Here is a numpy version of Sieve of Eratosthenes having both good complexity (lower than sorting an array of length n) and vectorization. Compared to @unutbu times this just as fast as the packages with 46 microsecons to find all primes below a million.
import numpy as np
def generate_primes(n):
is_prime = np.ones(n+1,dtype=bool)
is_prime[0:2] = False
for i in range(int(n**0.5)+1):
if is_prime[i]:
is_prime[i**2::i]=False
return np.where(is_prime)[0]
Timings:
import time
for i in range(2,10):
timer =time.time()
generate_primes(10**i)
print('n = 10^',i,' time =', round(time.time()-timer,6))
>> n = 10^ 2 time = 5.6e-05
>> n = 10^ 3 time = 6.4e-05
>> n = 10^ 4 time = 0.000114
>> n = 10^ 5 time = 0.000593
>> n = 10^ 6 time = 0.00467
>> n = 10^ 7 time = 0.177758
>> n = 10^ 8 time = 1.701312
>> n = 10^ 9 time = 19.322478
Upvotes: 1
Reputation: 130
Fastest prime sieve in Pure Python:
from itertools import compress
def half_sieve(n):
"""
Returns a list of prime numbers less than `n`.
"""
if n <= 2:
return []
sieve = bytearray([True]) * (n // 2)
for i in range(3, int(n ** 0.5) + 1, 2):
if sieve[i // 2]:
sieve[i * i // 2::i] = bytearray((n - i * i - 1) // (2 * i) + 1)
primes = list(compress(range(1, n, 2), sieve))
primes[0] = 2
return primes
I optimised Sieve of Eratosthenes for speed and memory.
from time import clock
import platform
def benchmark(iterations, limit):
start = clock()
for x in range(iterations):
half_sieve(limit)
end = clock() - start
print(f'{end/iterations:.4f} seconds for primes < {limit}')
if __name__ == '__main__':
print(platform.python_version())
print(platform.platform())
print(platform.processor())
it = 10
for pw in range(4, 9):
benchmark(it, 10**pw)
Output
>>> 3.6.7
>>> Windows-10-10.0.17763-SP0
>>> Intel64 Family 6 Model 78 Stepping 3, GenuineIntel
>>> 0.0003 seconds for primes < 10000
>>> 0.0021 seconds for primes < 100000
>>> 0.0204 seconds for primes < 1000000
>>> 0.2389 seconds for primes < 10000000
>>> 2.6702 seconds for primes < 100000000
Upvotes: 4
Reputation: 411
Here is two updated (pure Python 3.6) versions of one of the fastest functions,
from itertools import compress
def rwh_primes1v1(n):
""" Returns a list of primes < n for n > 2 """
sieve = bytearray([True]) * (n//2)
for i in range(3,int(n**0.5)+1,2):
if sieve[i//2]:
sieve[i*i//2::i] = bytearray((n-i*i-1)//(2*i)+1)
return [2,*compress(range(3,n,2), sieve[1:])]
def rwh_primes1v2(n):
""" Returns a list of primes < n for n > 2 """
sieve = bytearray([True]) * (n//2+1)
for i in range(1,int(n**0.5)//2+1):
if sieve[i]:
sieve[2*i*(i+1)::2*i+1] = bytearray((n//2-2*i*(i+1))//(2*i+1)+1)
return [2,*compress(range(3,n,2), sieve[1:])]
Upvotes: 9
Reputation: 5824
For Python 3
def rwh_primes2(n):
correction = (n%6>1)
n = {0:n,1:n-1,2:n+4,3:n+3,4:n+2,5:n+1}[n%6]
sieve = [True] * (n//3)
sieve[0] = False
for i in range(int(n**0.5)//3+1):
if sieve[i]:
k=3*i+1|1
sieve[ ((k*k)//3) ::2*k]=[False]*((n//6-(k*k)//6-1)//k+1)
sieve[(k*k+4*k-2*k*(i&1))//3::2*k]=[False]*((n//6-(k*k+4*k-2*k*(i&1))//6-1)//k+1)
return [2,3] + [3*i+1|1 for i in range(1,n//3-correction) if sieve[i]]
Upvotes: 3
Reputation: 1094
I tested some unutbu's functions, i computed it with hungred millions number
The winners are the functions that use numpy library,
Note: It would also interesting make a memory utilization test :)
Sample code
Complete code on my github repository
#!/usr/bin/env python
import lib
import timeit
import sys
import math
import datetime
import prettyplotlib as ppl
import numpy as np
import matplotlib.pyplot as plt
from prettyplotlib import brewer2mpl
primenumbers_gen = [
'sieveOfEratosthenes',
'ambi_sieve',
'ambi_sieve_plain',
'sundaram3',
'sieve_wheel_30',
'primesfrom3to',
'primesfrom2to',
'rwh_primes',
'rwh_primes1',
'rwh_primes2',
]
def human_format(num):
# https://stackoverflow.com/questions/579310/formatting-long-numbers-as-strings-in-python?answertab=active#tab-top
magnitude = 0
while abs(num) >= 1000:
magnitude += 1
num /= 1000.0
# add more suffixes if you need them
return '%.2f%s' % (num, ['', 'K', 'M', 'G', 'T', 'P'][magnitude])
if __name__=='__main__':
# Vars
n = 10000000 # number itereration generator
nbcol = 5 # For decompose prime number generator
nb_benchloop = 3 # Eliminate false positive value during the test (bench average time)
datetimeformat = '%Y-%m-%d %H:%M:%S.%f'
config = 'from __main__ import n; import lib'
primenumbers_gen = {
'sieveOfEratosthenes': {'color': 'b'},
'ambi_sieve': {'color': 'b'},
'ambi_sieve_plain': {'color': 'b'},
'sundaram3': {'color': 'b'},
'sieve_wheel_30': {'color': 'b'},
# # # 'primesfrom2to': {'color': 'b'},
'primesfrom3to': {'color': 'b'},
# 'rwh_primes': {'color': 'b'},
# 'rwh_primes1': {'color': 'b'},
'rwh_primes2': {'color': 'b'},
}
# Get n in command line
if len(sys.argv)>1:
n = int(sys.argv[1])
step = int(math.ceil(n / float(nbcol)))
nbs = np.array([i * step for i in range(1, int(nbcol) + 1)])
set2 = brewer2mpl.get_map('Paired', 'qualitative', 12).mpl_colors
print datetime.datetime.now().strftime(datetimeformat)
print("Compute prime number to %(n)s" % locals())
print("")
results = dict()
for pgen in primenumbers_gen:
results[pgen] = dict()
benchtimes = list()
for n in nbs:
t = timeit.Timer("lib.%(pgen)s(n)" % locals(), setup=config)
execute_times = t.repeat(repeat=nb_benchloop,number=1)
benchtime = np.mean(execute_times)
benchtimes.append(benchtime)
results[pgen] = {'benchtimes':np.array(benchtimes)}
fig, ax = plt.subplots(1)
plt.ylabel('Computation time (in second)')
plt.xlabel('Numbers computed')
i = 0
for pgen in primenumbers_gen:
bench = results[pgen]['benchtimes']
avgs = np.divide(bench,nbs)
avg = np.average(bench, weights=nbs)
# Compute linear regression
A = np.vstack([nbs, np.ones(len(nbs))]).T
a, b = np.linalg.lstsq(A, nbs*avgs)[0]
# Plot
i += 1
#label="%(pgen)s" % locals()
#ppl.plot(nbs, nbs*avgs, label=label, lw=1, linestyle='--', color=set2[i % 12])
label="%(pgen)s avg" % locals()
ppl.plot(nbs, a * nbs + b, label=label, lw=2, color=set2[i % 12])
print datetime.datetime.now().strftime(datetimeformat)
ppl.legend(ax, loc='upper left', ncol=4)
# Change x axis label
ax.get_xaxis().get_major_formatter().set_scientific(False)
fig.canvas.draw()
labels = [human_format(int(item.get_text())) for item in ax.get_xticklabels()]
ax.set_xticklabels(labels)
ax = plt.gca()
plt.show()
Upvotes: 3
Reputation: 129
It's all written and tested. So there is no need to reinvent the wheel.
python -m timeit -r10 -s"from sympy import sieve" "primes = list(sieve.primerange(1, 10**6))"
gives us a record breaking 12.2 msec!
10 loops, best of 10: 12.2 msec per loop
If this is not fast enough, you can try PyPy:
pypy -m timeit -r10 -s"from sympy import sieve" "primes = list(sieve.primerange(1, 10**6))"
which results in:
10 loops, best of 10: 2.03 msec per loop
The answer with 247 up-votes lists 15.9 ms for the best solution. Compare this!!!
Upvotes: 4
Reputation: 163
If you accept itertools but not numpy, here is an adaptation of rwh_primes2 for Python 3 that runs about twice as fast on my machine. The only substantial change is using a bytearray instead of a list for the boolean, and using compress instead of a list comprehension to build the final list. (I'd add this as a comment like moarningsun if I were able.)
import itertools
izip = itertools.zip_longest
chain = itertools.chain.from_iterable
compress = itertools.compress
def rwh_primes2_python3(n):
""" Input n>=6, Returns a list of primes, 2 <= p < n """
zero = bytearray([False])
size = n//3 + (n % 6 == 2)
sieve = bytearray([True]) * size
sieve[0] = False
for i in range(int(n**0.5)//3+1):
if sieve[i]:
k=3*i+1|1
start = (k*k+4*k-2*k*(i&1))//3
sieve[(k*k)//3::2*k]=zero*((size - (k*k)//3 - 1) // (2 * k) + 1)
sieve[ start ::2*k]=zero*((size - start - 1) // (2 * k) + 1)
ans = [2,3]
poss = chain(izip(*[range(i, n, 6) for i in (1,5)]))
ans.extend(compress(poss, sieve))
return ans
Comparisons:
>>> timeit.timeit('primes.rwh_primes2(10**6)', setup='import primes', number=1)
0.0652179726976101
>>> timeit.timeit('primes.rwh_primes2_python3(10**6)', setup='import primes', number=1)
0.03267321276325674
and
>>> timeit.timeit('primes.rwh_primes2(10**8)', setup='import primes', number=1)
6.394284538007014
>>> timeit.timeit('primes.rwh_primes2_python3(10**8)', setup='import primes', number=1)
3.833829450302801
Upvotes: 11
Reputation: 879471
Warning: timeit
results may vary due to differences in hardware or
version 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.
+---------------------+-------+
| Method | ms |
+---------------------+-------+
| rwh_primes1 | 43.0 |
| sieveOfAtkin | 46.4 |
| rwh_primes | 57.4 |
| sieve_wheel_30 | 63.0 |
| rwh_primes2 | 67.8 |
| sieveOfEratosthenes | 147.0 |
| ambi_sieve_plain | 152.0 |
| sundaram3 | 194.0 |
+---------------------+-------+
Of the plain Python methods tested, without psyco, for n=1000000, rwh_primes2 was the fastest.
+---------------------+-------+
| Method | ms |
+---------------------+-------+
| rwh_primes2 | 68.1 |
| rwh_primes1 | 93.7 |
| rwh_primes | 94.6 |
| sieve_wheel_30 | 97.4 |
| sieveOfEratosthenes | 178.0 |
| ambi_sieve_plain | 286.0 |
| sieveOfAtkin | 314.0 |
| sundaram3 | 416.0 |
+---------------------+-------+
Of all the methods tested, allowing numpy, for n=1000000, primesfrom2to was the fastest tested.
+---------------------+-------+
| Method | ms |
+---------------------+-------+
| primesfrom2to | 15.9 |
| primesfrom3to | 18.4 |
| ambi_sieve | 29.3 |
+---------------------+-------+
Timings were measured using the command:
python -mtimeit -s"import primes" "primes.{method}(1000000)"
with {method}
replaced by each of the method names.
primes.py:
#!/usr/bin/env python
import psyco; psyco.full()
from math import sqrt, ceil
import numpy as np
def rwh_primes(n):
# https://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188
""" Returns a list of primes < n """
sieve = [True] * n
for i in xrange(3,int(n**0.5)+1,2):
if sieve[i]:
sieve[i*i::2*i]=[False]*((n-i*i-1)/(2*i)+1)
return [2] + [i for i in xrange(3,n,2) if sieve[i]]
def rwh_primes1(n):
# https://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188
""" Returns a list of primes < n """
sieve = [True] * (n/2)
for i in xrange(3,int(n**0.5)+1,2):
if sieve[i/2]:
sieve[i*i/2::i] = [False] * ((n-i*i-1)/(2*i)+1)
return [2] + [2*i+1 for i in xrange(1,n/2) if sieve[i]]
def rwh_primes2(n):
# https://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188
""" Input n>=6, Returns a list of primes, 2 <= p < n """
correction = (n%6>1)
n = {0:n,1:n-1,2:n+4,3:n+3,4:n+2,5:n+1}[n%6]
sieve = [True] * (n/3)
sieve[0] = False
for i in xrange(int(n**0.5)/3+1):
if sieve[i]:
k=3*i+1|1
sieve[ ((k*k)/3) ::2*k]=[False]*((n/6-(k*k)/6-1)/k+1)
sieve[(k*k+4*k-2*k*(i&1))/3::2*k]=[False]*((n/6-(k*k+4*k-2*k*(i&1))/6-1)/k+1)
return [2,3] + [3*i+1|1 for i in xrange(1,n/3-correction) if sieve[i]]
def sieve_wheel_30(N):
# http://zerovolt.com/?p=88
''' Returns a list of primes <= N using wheel criterion 2*3*5 = 30
Copyright 2009 by zerovolt.com
This code is free for non-commercial purposes, in which case you can just leave this comment as a credit for my work.
If you need this code for commercial purposes, please contact me by sending an email to: info [at] zerovolt [dot] com.'''
__smallp = ( 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, 113, 127, 131, 137, 139,
149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227,
229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311,
313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401,
409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491,
499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599,
601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683,
691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797,
809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887,
907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997)
wheel = (2, 3, 5)
const = 30
if N < 2:
return []
if N <= const:
pos = 0
while __smallp[pos] <= N:
pos += 1
return list(__smallp[:pos])
# make the offsets list
offsets = (7, 11, 13, 17, 19, 23, 29, 1)
# prepare the list
p = [2, 3, 5]
dim = 2 + N // const
tk1 = [True] * dim
tk7 = [True] * dim
tk11 = [True] * dim
tk13 = [True] * dim
tk17 = [True] * dim
tk19 = [True] * dim
tk23 = [True] * dim
tk29 = [True] * dim
tk1[0] = False
# help dictionary d
# d[a , b] = c ==> if I want to find the smallest useful multiple of (30*pos)+a
# on tkc, then I need the index given by the product of [(30*pos)+a][(30*pos)+b]
# in general. If b < a, I need [(30*pos)+a][(30*(pos+1))+b]
d = {}
for x in offsets:
for y in offsets:
res = (x*y) % const
if res in offsets:
d[(x, res)] = y
# another help dictionary: gives tkx calling tmptk[x]
tmptk = {1:tk1, 7:tk7, 11:tk11, 13:tk13, 17:tk17, 19:tk19, 23:tk23, 29:tk29}
pos, prime, lastadded, stop = 0, 0, 0, int(ceil(sqrt(N)))
# inner functions definition
def del_mult(tk, start, step):
for k in xrange(start, len(tk), step):
tk[k] = False
# end of inner functions definition
cpos = const * pos
while prime < stop:
# 30k + 7
if tk7[pos]:
prime = cpos + 7
p.append(prime)
lastadded = 7
for off in offsets:
tmp = d[(7, off)]
start = (pos + prime) if off == 7 else (prime * (const * (pos + 1 if tmp < 7 else 0) + tmp) )//const
del_mult(tmptk[off], start, prime)
# 30k + 11
if tk11[pos]:
prime = cpos + 11
p.append(prime)
lastadded = 11
for off in offsets:
tmp = d[(11, off)]
start = (pos + prime) if off == 11 else (prime * (const * (pos + 1 if tmp < 11 else 0) + tmp) )//const
del_mult(tmptk[off], start, prime)
# 30k + 13
if tk13[pos]:
prime = cpos + 13
p.append(prime)
lastadded = 13
for off in offsets:
tmp = d[(13, off)]
start = (pos + prime) if off == 13 else (prime * (const * (pos + 1 if tmp < 13 else 0) + tmp) )//const
del_mult(tmptk[off], start, prime)
# 30k + 17
if tk17[pos]:
prime = cpos + 17
p.append(prime)
lastadded = 17
for off in offsets:
tmp = d[(17, off)]
start = (pos + prime) if off == 17 else (prime * (const * (pos + 1 if tmp < 17 else 0) + tmp) )//const
del_mult(tmptk[off], start, prime)
# 30k + 19
if tk19[pos]:
prime = cpos + 19
p.append(prime)
lastadded = 19
for off in offsets:
tmp = d[(19, off)]
start = (pos + prime) if off == 19 else (prime * (const * (pos + 1 if tmp < 19 else 0) + tmp) )//const
del_mult(tmptk[off], start, prime)
# 30k + 23
if tk23[pos]:
prime = cpos + 23
p.append(prime)
lastadded = 23
for off in offsets:
tmp = d[(23, off)]
start = (pos + prime) if off == 23 else (prime * (const * (pos + 1 if tmp < 23 else 0) + tmp) )//const
del_mult(tmptk[off], start, prime)
# 30k + 29
if tk29[pos]:
prime = cpos + 29
p.append(prime)
lastadded = 29
for off in offsets:
tmp = d[(29, off)]
start = (pos + prime) if off == 29 else (prime * (const * (pos + 1 if tmp < 29 else 0) + tmp) )//const
del_mult(tmptk[off], start, prime)
# now we go back to top tk1, so we need to increase pos by 1
pos += 1
cpos = const * pos
# 30k + 1
if tk1[pos]:
prime = cpos + 1
p.append(prime)
lastadded = 1
for off in offsets:
tmp = d[(1, off)]
start = (pos + prime) if off == 1 else (prime * (const * pos + tmp) )//const
del_mult(tmptk[off], start, prime)
# time to add remaining primes
# if lastadded == 1, remove last element and start adding them from tk1
# this way we don't need an "if" within the last while
if lastadded == 1:
p.pop()
# now complete for every other possible prime
while pos < len(tk1):
cpos = const * pos
if tk1[pos]: p.append(cpos + 1)
if tk7[pos]: p.append(cpos + 7)
if tk11[pos]: p.append(cpos + 11)
if tk13[pos]: p.append(cpos + 13)
if tk17[pos]: p.append(cpos + 17)
if tk19[pos]: p.append(cpos + 19)
if tk23[pos]: p.append(cpos + 23)
if tk29[pos]: p.append(cpos + 29)
pos += 1
# remove exceeding if present
pos = len(p) - 1
while p[pos] > N:
pos -= 1
if pos < len(p) - 1:
del p[pos+1:]
# return p list
return p
def sieveOfEratosthenes(n):
"""sieveOfEratosthenes(n): return the list of the primes < n."""
# Code from: <[email protected]>, Nov 30 2006
# http://groups.google.com/group/comp.lang.python/msg/f1f10ced88c68c2d
if n <= 2:
return []
sieve = range(3, n, 2)
top = len(sieve)
for si in sieve:
if si:
bottom = (si*si - 3) // 2
if bottom >= top:
break
sieve[bottom::si] = [0] * -((bottom - top) // si)
return [2] + [el for el in sieve if el]
def sieveOfAtkin(end):
"""sieveOfAtkin(end): return a list of all the prime numbers <end
using the Sieve of Atkin."""
# Code by Steve Krenzel, <[email protected]>, improved
# Code: https://web.archive.org/web/20080324064651/http://krenzel.info/?p=83
# Info: http://en.wikipedia.org/wiki/Sieve_of_Atkin
assert end > 0
lng = ((end-1) // 2)
sieve = [False] * (lng + 1)
x_max, x2, xd = int(sqrt((end-1)/4.0)), 0, 4
for xd in xrange(4, 8*x_max + 2, 8):
x2 += xd
y_max = int(sqrt(end-x2))
n, n_diff = x2 + y_max*y_max, (y_max << 1) - 1
if not (n & 1):
n -= n_diff
n_diff -= 2
for d in xrange((n_diff - 1) << 1, -1, -8):
m = n % 12
if m == 1 or m == 5:
m = n >> 1
sieve[m] = not sieve[m]
n -= d
x_max, x2, xd = int(sqrt((end-1) / 3.0)), 0, 3
for xd in xrange(3, 6 * x_max + 2, 6):
x2 += xd
y_max = int(sqrt(end-x2))
n, n_diff = x2 + y_max*y_max, (y_max << 1) - 1
if not(n & 1):
n -= n_diff
n_diff -= 2
for d in xrange((n_diff - 1) << 1, -1, -8):
if n % 12 == 7:
m = n >> 1
sieve[m] = not sieve[m]
n -= d
x_max, y_min, x2, xd = int((2 + sqrt(4-8*(1-end)))/4), -1, 0, 3
for x in xrange(1, x_max + 1):
x2 += xd
xd += 6
if x2 >= end: y_min = (((int(ceil(sqrt(x2 - end))) - 1) << 1) - 2) << 1
n, n_diff = ((x*x + x) << 1) - 1, (((x-1) << 1) - 2) << 1
for d in xrange(n_diff, y_min, -8):
if n % 12 == 11:
m = n >> 1
sieve[m] = not sieve[m]
n += d
primes = [2, 3]
if end <= 3:
return primes[:max(0,end-2)]
for n in xrange(5 >> 1, (int(sqrt(end))+1) >> 1):
if sieve[n]:
primes.append((n << 1) + 1)
aux = (n << 1) + 1
aux *= aux
for k in xrange(aux, end, 2 * aux):
sieve[k >> 1] = False
s = int(sqrt(end)) + 1
if s % 2 == 0:
s += 1
primes.extend([i for i in xrange(s, end, 2) if sieve[i >> 1]])
return primes
def ambi_sieve_plain(n):
s = range(3, n, 2)
for m in xrange(3, int(n**0.5)+1, 2):
if s[(m-3)/2]:
for t in xrange((m*m-3)/2,(n>>1)-1,m):
s[t]=0
return [2]+[t for t in s if t>0]
def sundaram3(max_n):
# https://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python/2073279#2073279
numbers = range(3, max_n+1, 2)
half = (max_n)//2
initial = 4
for step in xrange(3, max_n+1, 2):
for i in xrange(initial, half, step):
numbers[i-1] = 0
initial += 2*(step+1)
if initial > half:
return [2] + filter(None, numbers)
################################################################################
# Using Numpy:
def ambi_sieve(n):
# http://tommih.blogspot.com/2009/04/fast-prime-number-generator.html
s = np.arange(3, n, 2)
for m in xrange(3, int(n ** 0.5)+1, 2):
if s[(m-3)/2]:
s[(m*m-3)/2::m]=0
return np.r_[2, s[s>0]]
def primesfrom3to(n):
# https://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188
""" Returns a array of primes, p < n """
assert n>=2
sieve = np.ones(n/2, dtype=np.bool)
for i in xrange(3,int(n**0.5)+1,2):
if sieve[i/2]:
sieve[i*i/2::i] = False
return np.r_[2, 2*np.nonzero(sieve)[0][1::]+1]
def primesfrom2to(n):
# https://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188
""" Input n>=6, Returns a array of primes, 2 <= p < n """
sieve = np.ones(n/3 + (n%6==2), dtype=np.bool)
sieve[0] = False
for i in xrange(int(n**0.5)/3+1):
if sieve[i]:
k=3*i+1|1
sieve[ ((k*k)/3) ::2*k] = False
sieve[(k*k+4*k-2*k*(i&1))/3::2*k] = False
return np.r_[2,3,((3*np.nonzero(sieve)[0]+1)|1)]
if __name__=='__main__':
import itertools
import sys
def test(f1,f2,num):
print('Testing {f1} and {f2} return same results'.format(
f1=f1.func_name,
f2=f2.func_name))
if not all([a==b for a,b in itertools.izip_longest(f1(num),f2(num))]):
sys.exit("Error: %s(%s) != %s(%s)"%(f1.func_name,num,f2.func_name,num))
n=1000000
test(sieveOfAtkin,sieveOfEratosthenes,n)
test(sieveOfAtkin,ambi_sieve,n)
test(sieveOfAtkin,ambi_sieve_plain,n)
test(sieveOfAtkin,sundaram3,n)
test(sieveOfAtkin,sieve_wheel_30,n)
test(sieveOfAtkin,primesfrom3to,n)
test(sieveOfAtkin,primesfrom2to,n)
test(sieveOfAtkin,rwh_primes,n)
test(sieveOfAtkin,rwh_primes1,n)
test(sieveOfAtkin,rwh_primes2,n)
Running the script tests that all implementations give the same result.
Upvotes: 417
Reputation: 137574
It's instructive to write your own prime finding code, but it's also useful to have a fast reliable library at hand. I wrote a wrapper around the C++ library primesieve, named it primesieve-python
Try it pip install primesieve
import primesieve
primes = primesieve.generate_primes(10**8)
I'd be curious to see the speed compared.
Upvotes: 8
Reputation: 137574
If you don't want to reinvent the wheel, you can install the symbolic maths library sympy (yes it's Python 3 compatible)
pip install sympy
And use the primerange function
from sympy import sieve
primes = list(sieve.primerange(1, 10**6))
Upvotes: 15
Reputation: 1449
This is the way you can compare with others.
# You have to list primes upto n
nums = xrange(2, n)
for i in range(2, 10):
nums = filter(lambda s: s==i or s%i, nums)
print nums
So simple...
Upvotes: -4
Reputation: 881635
There's a pretty neat sample from the Python Cookbook here -- the fastest version proposed on that URL is:
import itertools
def erat2( ):
D = { }
yield 2
for q in itertools.islice(itertools.count(3), 0, None, 2):
p = D.pop(q, None)
if p is None:
D[q*q] = q
yield q
else:
x = p + q
while x in D or not (x&1):
x += p
D[x] = p
so that would give
def get_primes_erat(n):
return list(itertools.takewhile(lambda p: p<n, erat2()))
Measuring at the shell prompt (as I prefer to do) with this code in pri.py, I observe:
$ python2.5 -mtimeit -s'import pri' 'pri.get_primes(1000000)'
10 loops, best of 3: 1.69 sec per loop
$ python2.5 -mtimeit -s'import pri' 'pri.get_primes_erat(1000000)'
10 loops, best of 3: 673 msec per loop
so it looks like the Cookbook solution is over twice as fast.
Upvotes: 43
Reputation: 131
I'm slow responding to this question but it seemed like a fun exercise. I'm using numpy which might be cheating and I doubt this method is the fastest but it should be clear. It sieves a Boolean array referring to its indices only and elicits prime numbers from the indices of all True values. No modulo needed.
import numpy as np
def ajs_primes3a(upto):
mat = np.ones((upto), dtype=bool)
mat[0] = False
mat[1] = False
mat[4::2] = False
for idx in range(3, int(upto ** 0.5)+1, 2):
mat[idx*2::idx] = False
return np.where(mat == True)[0]
Upvotes: 0
Reputation: 2640
I collected several prime number sieves over time. The fastest on my computer is this:
from time import time
# 175 ms for all the primes up to the value 10**6
def primes_sieve(limit):
a = [True] * limit
a[0] = a[1] = False
#a[2] = True
for n in xrange(4, limit, 2):
a[n] = False
root_limit = int(limit**.5)+1
for i in xrange(3,root_limit):
if a[i]:
for n in xrange(i*i, limit, 2*i):
a[n] = False
return a
LIMIT = 10**6
s=time()
primes = primes_sieve(LIMIT)
print time()-s
Upvotes: 0