大整数分解

【概述】

大整数分解目前仍是世界级难题,是非常重要的研究方向,其有很多种算法,性能上各有差异,本文仅介绍试除法、Fermat 算法、Pollard Rho 算法。

【试除法】

试除法也叫穷举法,是整数分解算法中最简单和最容易理解的算法,但也是效率最低的算法。

试除法是用小于等于 n 的每个素数去试除待分解的整数,如果找到一个数能够整除除尽,这个数就是待分解整数的因子。

试除法一定能够找到 n 的因子,因为它检查 n 的所有可能的因子,所以如果这个算法失败,也就证明了 n 是个素数,因此,试除法也常用来判断一个数是不是质数。

bool judge(int n)
{
    if(n==1)//1不是一个有效因数
        return false;

    for(int i=2;i<sqrt(n);i++)//如果能被整除,说明是因数
        if(n%i==0)
            retrun true;

    return false;
}

【Fermat 算法】

Fermat 算法分解大数的效率并不高,但比起试除法要好了很多,且每次计算都是计算出 N 的一个因子,更降低了其效率。

1.费马整数分解

对于一个任意的偶数,我们都可以通过不断提出为 2 的质因子使其最终简化为一个 2 的 n 次幂与一个奇数,因此,任意一个奇数都可以表示为:N=2*n+1

若这个奇数 N 是一个合数,根据唯一分解定理,其一定可以写成 N=c*d 的形式,不难发现,式中 c、d 均为奇数

设:c>d,令 a=(c+d)/2,b=(c-d)/2

可得:N=c*d=a*a-b*b

例如:

\begin{matrix}1=1*1=1^2-0^2 \\3 = 3*1 = 2^2 -1^2 \\5 = 5*1 = 3^2 - 2^2 \\ 7 = 7*1 = 4^2 - 3^2 \\ 9 = 3*3 = 3^2 - 0^2 \end{matrix}

扫描二维码关注公众号,回复: 2540584 查看本文章

2.费马因式分解算法

由于 a^2-N\geqslant b^2\geqslant 0

因此 a^2\geqslant N

即:a\geqslant \sqrt{c*d}=\sqrt{N}

因此,我们可以从 a=\sqrt{N} 开始枚举,计算 a^2-N 为完全平方数即可求出 a、b,从而可以求得:c=a+b,d=a-b(a>b)

int res[N];
void Fermat(int n)
{
    int a,b,temp;

    a=sqrt(n);
    if(a*a<n)
        a++;
    
    while(1)//y^2=x^2-n
    {
        temp=a*a-n;
        b=sqrt(a*a-n);

        if(b*b==temp)
            break;
        a++;
    }
    
    res[0]=a;//存储a的值
    res[1]=b;//存储b的值
}

【Pollard Rho 算法】

为进一步提高效率,解决因数太多无法存储的问题,我们有了 Pollard Rho 算法。

1.算法原理

其原理已知待分解的大整数 n,再通过某种方法得到两个整数 a、b,计算 p=GCD(|a-b|,n),直到 p不为1,或 a、b 出现循环为止,然后再判断 p 的值,若 p=n 或 p=1,那么返回的 n 是一个质数,否则返回的 p 是 n 的一个因子,因此我们可以递归的计算 Pollard(p) 与 Pollard(n/p) ,从而求出 n 所有的因子。

实际操作中,我们通常使用函数:x[i+1]=(x[i]*x[i]+c) mod\:n 来不断生成伪随机数,用于逐步迭代计算 a、b 的值。

实践中,常取 c=1,再任意取两初值 a、b,即:b=a*a+1,在下一次计算中,将 b 的值赋给 a,再次使用上式来计算新的 b 的值,直至 a、b 出现循环。

但是这样判断 a、b 的循环十分麻烦,例如生成伪随机数为:2,10,16,23,29,13,16,23,29,13...时,很难判断循环,因此我们可以采用 Floyd 判环算法来判断循环。

2.Floyd 判环算法实现Pollard Rho 算法

利用多项式 f(x) 迭代出 x_0,x_1,...,x_k 的值,然后设定 x、y 的初值,选用多项式进行迭代

每次令:\left\{\begin{matrix} x=f(x) \\ y=f(f(y)) \end{matrix}\right.,即:\left\{\begin{matrix}x=x_k \\ y=x_{2k} \end{matrix}\right.

当 x=y 时即出现循环

int GCD(int a,int b)
{
    return b?GCD(b,a%b):a;
}
int Pow_Mod(int a, int b, int m)
{
    int res=1;
    while(b)
    {
        if(b&1)
            res=(res*a)%m;
        a=(a*a)%m;
        b>>=1;
    }
}

int Pollard_Rho(int n,int a)
{
    int x=2,y=2,c=1;//设置初值x=y=2,c=1
    while(c==1)
    {
        x=Pow_Mod(x, x, n)+a;
        y=Pow_Mod(y, y, n)+a;
        c=GCD((x>=y?x-y:y-x), n);
    }
    if(c==n)//如果相同,说明出现循环
        return pollard_rho(n,a+1);
    return c;
}

猜你喜欢

转载自blog.csdn.net/u011815404/article/details/81335633