Miller-Rabin素数测试算法

【作用】

有时候我们想快速的知道一个数是不是素数,而这个数又特别的大导致 O( \sqrt\, n ) 的算法不能通过,这时候我们可以对其进行 Miller-Rabin 素数测试,可以大概率测出其是否为素数。

 

【两个基础理论】

(1)费马小定理:当 p 为质数,有 a^{p-1}\equiv 1(mod \: \, p),不过反过来不一定成立,也就是说,如果 ap 互质,且 a^{p-1}\equiv 1(mod \: \, p),不能推出 p 是质数,比如 Carmichael 数(这个就自行百度吧)

(2)二次探测:如果 p 是一个素数,0 < x < p, 则方程 x^{2}\equiv 1(mod\: \, p) 的解为 x = 1x = p - 1

 

【两个基本理论的证明】

证明转载费马小定律&二次探测的证明

Miller-Rabin素数测试算法_第1张图片

 

【算法流程】

(1)对于偶数和 0,1,2 可以直接判断。

(2)设要测试的数为 x,我们取一个较小的质数 a,设 s,t,满足 2^s\cdot t=x-1(其中 t 是奇数)。

(3)我们先算出 a^t,然后不断地平方并且进行二次探测(进行 s 次)。

(4)最后我们根据费马小定律,如果最后 a^{x-1}\not\equiv 1(mod \:\, x),则说明 x 为合数。

(5)多次取不同的 a 进行 Miller-Rabin 素数测试,这样可以使正确性更高

 

【备注】

(1)我们可以多选择几个 a,如果全部通过,那么 x 大概率是质数。

(2)Miller-Rabin 素数测试中,“大概率”意味着概率非常大,基本上可以放心使用。

(3)当 a 取遍小等于 30 的所有素数时,可以证明 int 范围内的数不会出错。

(4)代码中我用的 int 类型,不过实际上 Miller-Rabin 素数测试可以承受更大的范围。

(5)另外,如果是求一个 long long 类型的平方,可能会爆掉,因此有时我们要用“快速积”,不能直接乘。

 

【代码】

#include
#include
#include
using namespace std;
int prime[10]={2,3,5,7,11,13,17,19,23,29};
int Quick_Multiply(int a,int b,int c)  //快速积(和快速幂差不多) 
{
    long long ans=0,res=a;
    while(b)
    {
        if(b&1)
          ans=(ans+res)%c;
        res=(res+res)%c;
        b>>=1;
    }
    return (int)ans;
}
int Quick_Power(int a,int b,int c)     //快速幂,这里就不赘述了 
{
    int ans=1,res=a;
    while(b)
    {
        if(b&1)
          ans=Quick_Multiply(ans,res,c);
        res=Quick_Multiply(res,res,c);
        b>>=1;
    }
    return ans;
}
bool Miller_Rabin(int x)     //判断素数 
{
    int i,j,k;
    int s=0,t=x-1;
    if(x==2)  return true;   //2是素数 
    if(x<2||!(x&1))  return false;     //如果x是偶数或者是0,1,那它不是素数 
    while(!(t&1))  //将x分解成(2^s)*t的样子 
    {
        s++;
        t>>=1;
    }
    for(i=0;i<10&&prime[i]

 

你可能感兴趣的:(#,知识点)