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

发布于 2024-10-25 10:29:55 字数 879 浏览 1 评论 0 原文

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

心碎的声音 2024-11-01 10:29:55

我能找到的最好的改进是从模函数中完全删除 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. Using while n > Mp: instead of while n.bit_length() > p: also saved some time.

孤蝉 2024-11-01 10:29:55

在 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 的长度减半而不是去掉 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:

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

[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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文