4.2 Pollard p-1算法

文章目录

算法

  1974年,John Pollard发明了p-1算法,其灵感来自于费马小定理。p-1算法一个重要的概念就是B-powersmooth,这个不太好翻译,power,幂,smooth,光滑,就叫幂滑吧。其定义如下,对于质数p,将p-1进行质因数分解,最大的因子 d k d^k dk就是B,而这个质数就是B-powersmooth。举个例子,质数p=1303, p − 1 = 1302 = 2 ⋅ 3 ⋅ 7 ⋅ 31 p-1=1302=2\cdot3\cdot7\cdot31 p1=1302=23731,那么质数1303就是31-powersmooth。再举个例子,质数3697, p − 1 = 3696 = 2 4 ⋅ 3 ⋅ 7 ⋅ 11 p-1=3696=2^4\cdot3\cdot7\cdot11 p1=3696=243711,那么3697就是16-powersmooth。
  Pollard p-1算法基于费马小定理。费马小定理我们已经讲过无数遍了,实际上很多算法都是基于费马小定理的,比如米勒罗宾素性检验。我们从费马小定理开始展开讲讲,其公式如下:
a p − 1 ≡ 1    m o d    p a^{p-1}\equiv1\;mod\;p ap11modp
  假使我们要对整数n进行质因数分解,他的其中一个质因数是p,数学里的整除符号是 p    ∣    n p\;|\;n pn。对于p,有:
d = a p − 1 − 1 = 0    m o d    p d=a^{p-1}-1=0\;mod\;p d=ap11=0modp
  所以d是p的倍数,也就是 p    ∣    d p\;|\;d pd,可以得到 p = g c d ( d , n ) p=gcd(d,n) p=gcd(d,n)。讲得这么复杂,其实就是:
g c d ( a p − 1 − 1 , n ) = p gcd(a^{p-1}-1,n)=p gcd(ap11,n)=p
  当然不可能一个个地尝试,那么和原始质因数分解没什么区别。Pollard p-1算法采用了一种随机数的策略。如果随机不出结果,那么就从小于B(这个B代表B-powersmooth)的质数列表里去连成,组成上述公式中的d,直到质数列表被用尽。

Python实现

# _*_ encoding:utf-8 _*_

import random


def gcd(m, n):

    if m < n:
        m, n = n, m
    while m % n != 0:
        m, n = n, m % n
    return n


def sieve(n):
    mpfs = [0] * (n + 1)
    pn = []
    for i in range(2, n + 1):
        mpf = mpfs[i]
        if mpf == 0:
            pn.append(i)
            mpf = i
        for p in pn:
            if p > mpf:
                break
            x = p * i
            if x > n:
                break
            mpfs[x] = p
    return pn


def pollard(n):
    b = 10_0000
    while b <= 100_0000:
        a = random.randint(2, n - 1)
        g = gcd(a, n)
        if g > 1:
            return g, n // g
        for p in sieve(b):
            if p >= b:
                continue

            p_power = 1
            while p_power * p <= b:
                p_power *= p
            g = gcd(p_power - 1, n)
            if g > 1 and g < n:
                return g, n // g
        b <<= 1
    return 1, n

def factor(n):
    factors = []
    stack = [n]
    while len(stack) > 0:
        x = stack.pop()
        if x == 2:
            factors.insert(0, x)
            continue
        p, q = pollard(x) if x & 1 == 1 else (2, x >> 1)
        if p == 1:
            factors.insert(0, q)
        else:
            stack.append(p)
            stack.append(q)
    return factors


if __name__ == '__main__':
    print(factor(200))

  测试结果:

[2, 2, 2, 5, 5]
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

醒过来摸鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值