我试图实施Miller-Rabin primality test,并且对为什么中型数字(约 7 位数)需要这么长时间(> 20 秒)感到困惑。我最终发现以下代码行是问题的根源:
x = a**d % n
(其中a
、d
和n
都是相似但不相等的中等大小的数字,**
是幂运算符,并且%
是模运算符)
然后我尝试用以下内容替换它:
x = pow(a, d, n)
相比之下,它几乎是瞬时的。
对于上下文,这是原始函数:
from random import randint
def primalityTest(n, k):
if n < 2:
return False
if n % 2 == 0:
return False
s = 0
d = n - 1
while d % 2 == 0:
s += 1
d >>= 1
for i in range(k):
rand = randint(2, n - 2)
x = rand**d % n # offending line
if x == 1 or x == n - 1:
continue
for r in range(s):
toReturn = True
x = pow(x, 2, n)
if x == 1:
return False
if x == n - 1:
toReturn = False
break
if toReturn:
return False
return True
print(primalityTest(2700643,1))
定时计算示例:
from timeit import timeit
a = 2505626
d = 1520321
n = 2700643
def testA():
print(a**d % n)
def testB():
print(pow(a, d, n))
print("time: %(time)fs" % {"time":timeit("testA()", setup="from __main__ import testA", number=1)})
print("time: %(time)fs" % {"time":timeit("testB()", setup="from __main__ import testB", number=1)})
输出(使用 PyPy 1.9.0 运行):
2642565
time: 23.785543s
2642565
time: 0.000030s
输出(使用 Python 3.3.0 运行,2.7.2 返回非常相似的时间):
2642565
time: 14.426975s
2642565
time: 0.000021s
还有一个相关的问题,为什么这个计算在使用 Python 2 或 3 运行时几乎是使用 PyPy 的两倍,而通常 PyPy更快?