Lucas-Lehmer 素性测试 测试素数以确定它们是否也是梅森素数。瓶颈之一是计算 (s**2 − 2) % (2**p - 1)
时的模运算。
使用按位运算可以大大加快速度(请参阅 LL 链接),迄今为止我所拥有的最好的结果是:
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) 进行测试。请记住,LL 测试中需要 p - 2 次模运算迭代,每次迭代都会以指数方式增加 s
,因此需要优化。
有没有办法使用纯Python(包括Python 3)进一步加快速度?有更好的办法吗?
The Lucas-Lehmer primality test tests prime numbers to determine whether they are also Mersenne primes. One of the bottlenecks is the modulus operation in the calculation of (s**2 − 2) % (2**p - 1)
.
Using bitwise operations can speed things up considerably (see the L-L link), the best I have so far being:
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
A simple test case is where p
has 5-9 digits and s
has 10,000+ digits (or more; not important what they are). Solutions can be tested by mod((s**2 - 2), p) == (s**2 - 2) % (2**p -1)
. Keep in mind that p - 2 iterations of this modulus operation are required in the L-L test, each with exponentially increasing s
, hence the need for optimization.
Is there a way to speed this up further, using pure Python (Python 3 included)? Is there a better way?
发布评论
评论(2)
我能找到的最好的改进是从模函数中完全删除
Mp = (1<
,并在开始 LL 测试迭代之前在 LL 函数中预先计算它。使用
while n > Mp:
而不是while n.bit_length() > p:
也节省了一些时间。The best improvement I could find was removing
Mp = (1<<p) - 1
from the modulus function altogether, and pre-calculating it in the L-L function before starting the iterations of the L-L test. Usingwhile n > Mp:
instead ofwhile n.bit_length() > p:
also saved some time.在 n 比 2^p 长得多的情况下,您可以通过执行以下操作来避免一些二次时间的痛苦:
[已编辑,因为我之前搞砸了格式;感谢本杰明指出了这一点。寓意:不要从空闲窗口复制粘贴到 SO 中。抱歉!]
(注意:将 n 的长度减半而不是去掉 p 的标准,以及 k1 的确切选择,都有点错误,但这并不重要,所以我没有费心去修复它们。)
如果我取 p=12345 和 n=9**200000 (是的,我知道 p 不是素数,但这在这里并不重要),那么速度大约快 13 倍。
不幸的是,这对您没有帮助,因为在 LL 测试中,n 永远不会大于 (2^p)^2。对不起。
In the case where n is much longer than 2^p, you can avoid some quadratic-time pain by doing something like this:
[EDITED because I screwed up the formatting before; thanks to Benjamin for pointing this out. Moral: don't copy-and-paste from an Idle window into SO. Sorry!]
(Note: the criterion for halving the length of n rather than taking p off it, and the exact choice of k1, are both a bit wrong, but it doesn't matter so I haven't bothered fixing them.)
If I take p=12345 and n=9**200000 (yes, I know p then isn't prime, but that doesn't matter here) then this is about 13 times faster.
Unfortunately this will not help you, because in the L-L test n is never bigger than about (2^p)^2. Sorry.