为了确定一个数是否是素数,有一个筛子和素数检验。# for large numbers, xrange will throw an error.
# OverflowError: Python int too large to convert to C long
# to get over this:
def mrange(start, stop, step):
while start < stop:
yield start
start += step
# benchmarked on an old single-core system with 2GB RAM.
from math import sqrt
def is_prime(num):
if num == 2:
return True
if (num < 2) or (num % 2 == 0):
return False
return all(num % i for i in mrange(3, int(sqrt(num)) + 1, 2))
# benchmark is_prime(100**10-1) using mrange
# 10000 calls, 53191 per second.
# 60006 function calls in 0.190 seconds.
这似乎是最快的。有另一个版本使用not any,您可以看到def is_prime(num)
# ...
return not any(num % i == 0 for i in mrange(3, int(sqrt(num)) + 1, 2))
然而,在基准测试中,我在测试100**10-1是否是素数时,得到了70006 function calls in 0.272 seconds.而不是all60006 function calls in 0.190 seconds.的使用。
如果你需要找到下一个最高素数,这个方法对你不起作用。你需要进行素性测试,我发现Miller-Rabin算法是个不错的选择。它稍微慢一点Fermat方法,但对伪素数更准确。在这个系统上使用上述方法需要5分钟。
Miller-Rabin算法:from random import randrange
def is_prime(n, k=10):
if n == 2:
return True
if not n & 1:
return False
def check(a, s, d, n):
x = pow(a, d, n)
if x == 1:
return True
for i in xrange(s - 1):
if x == n - 1:
return True
x = pow(x, 2, n)
return x == n - 1
s = 0
d = n - 1
while d % 2 == 0:
d >>= 1
s += 1
for i in xrange(k):
a = randrange(2, n - 1)
if not check(a, s, d, n):
return False
return True
Fermat算法:def is_prime(num):
if num == 2:
return True
if not num & 1:
return False
return pow(2, num-1, num) == 1
要获得下一个最高质数:def next_prime(num):
if (not num & 1) and (num != 2):
num += 1
if is_prime(num):
num += 2
while True:
if is_prime(num):
break
num += 2
return num
print next_prime(100**10-1) # returns `100000000000000000039`
# benchmark next_prime(100**10-1) using Miller-Rabin algorithm.
1000 calls, 337 per second.
258669 function calls in 2.971 seconds
使用Fermat测试,我们得到了45006 function calls in 0.885 seconds.的基准,但是您运行伪素数的几率更高。
所以,如果只需要检查一个数字是否是素数,那么第一个方法is_prime就可以了。如果使用mrange方法,它是最快的。
理想情况下,您需要存储由next_prime生成的素数,然后从中读取。
例如,将next_prime与Miller-Rabin算法一起使用:print next_prime(10^301)
# prints in 2.9s on the old single-core system, opposed to fermat's 2.8s
1000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000531
你不可能用return all(num % i for i in mrange(3, int(sqrt(num)) + 1, 2))及时完成这项工作。我在这个旧系统上都做不到。
为了确保next_prime(10^301)和Miller-Rabin产生正确的值,还使用Fermat和Solovay-Strassen算法对其进行了测试。
编辑:修复了next_prime中的错误