Lucas-Lehmer primality test测试素数以确定它们是否也是Mersenne primes。其中一个瓶颈是计算(s**2 − 2) % (2**p - 1)
时的模数运算。
使用按位运算可以大大加快速度(参见L-L链接),这是我迄今为止最好的:
def mod(n,p):
""" Returns the value of (s**2 - 2) % (2**p -1)"""
Mp = (1<<p) - 1
while n.bit_length() > p: # For Python < 2.7 use len(bin(n)) - 2 > p
n = (n & Mp) + (n >> p)
if n == Mp:
return 0
else:
return n
一个简单的测试用例是p
有5-9位数,s
有10,000+位数(或更多;不重要的是它们)。可以通过mod((s**2 - 2), p) == (s**2 - 2) % (2**p -1)
测试解决方案。请记住,在L-L测试中需要p - 2次迭代此模数运算,每次迭代都会呈指数增长s
,因此需要进行优化。
有没有办法使用纯Python(包括Python 3)进一步提高速度?还有更好的方法吗?
答案 0 :(得分:1)
我能找到的最好的改进是完全从模数函数中移除Mp = (1<<p) - 1
,并在开始L-L测试的迭代之前在L-L函数中预先计算它。使用while n > Mp:
代替while n.bit_length() > p:
也节省了一些时间。
答案 1 :(得分:0)
在n远大于2 ^ p的情况下,你可以通过这样的方式避免一些二次时间的痛苦:
def mod1(n,p):
while n.bit_length() > 3*p:
k = n.bit_length() // p
k1 = k>>1
k1p = k1*p
M = (1<<k1p)-1
n = (n & M) + (n >> k1p)
Mp = (1<<p)-1
while n.bit_length() > p:
n = (n&Mp) + (n>>p)
if n==Mp: return 0
return n
[编辑,因为我之前搞砸了格式化;感谢本杰明指出这一点。道德:不要从空闲窗口复制粘贴到SO中。遗憾!]
(注意:将n的长度减半而不是将其取下来的标准,以及k1的确切选择都有点不对,但这并不重要,所以我没有打扰它们。)
如果我采用p = 12345和n = 9 ** 200000(是的,我知道p不是素数,但这并不重要)那么这大约快了13倍。
不幸的是,这对你没有帮助,因为在L-L测试中,n从不大于约(2 ^ p)^ 2。遗憾。