Lucas-Lehmer素性测试的逐位模数更快

时间:2011-03-22 15:15:44

标签: python optimization bit-manipulation primes modulo

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)进一步提高速度?还有更好的方法吗?

2 个答案:

答案 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。遗憾。