我正在尝试实现Miller-Rabin素性测试,但对于中等大小的数字(约7位数),它花费的时间超过了20秒,让我感到困惑。最终,我发现以下代码行是问题的根源:
其中,
"
一个计时的例子:
输出结果(使用PyPy 1.9.0运行):
输出(在Python 3.3.0下运行,2.7.2返回非常相似的时间):
一个相关的问题是,为什么使用Python 2或3运行此计算几乎比使用PyPy快两倍,而通常情况下PyPy更快?
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更快?
x ** y % n
中,x
可能是一个实现了__pow__
的对象,并且根据随机数返回多个实现了__mod__
的对象,而这些对象以不同的方式取决于其他随机数等因素。 - BrenBarn.3 ** .4%.5
是完全合法的,但如果编译器将其转换为pow(.3,.4,.5)
,则会引发TypeError
。编译器必须能够知道a
,d
和n
保证是整数类型的值(或者可能只是特定类型的“int”,因为否则转换没有帮助),并且保证d
为非负数。这是JIT可以想象做到的事情,但是对于动态类型且没有推断的语言的静态编译器来说,这是不可能的。 - abarnert