Miller-Rabin素性测试

原文地址:https://www.cnblogs.com/Norlan/p/5350243.html

素数:若一个数x的约数仅仅只有1和他本身,则称之为素数,注意,1不是素数。

素数的性质:

1.素数无穷多,不存在最大素数

证明:假设最大素数存在且为p,我们可以用旧素数去构造新素数,设x=2*3*5*7*11*......*p+1,x不会被用来构造他的任何一个素数整除,当然由于素数之间也是互质的,没有被用来构造他的素数也不能整除他,只不过用来构造他的素数整除他的余数为1罢了。

2.存在任意长的一段连续区间,区间内的数全部都是合数

证明:当0<a<=n时,n!+a%a=0。而n!+2,n!+3,n!+4,......,n!+n都是合数(可分别被2,3,4,......,n整除),我们构造出了一段n-1的连续合数区间。

注:相邻素数之间的间隔可以是任意的可能是有问题的说法,通过上述的构造方法,我们可以构造出一个连续合数区间,使得它的长度>=n-1,但是,具体这个长度是多少是未知的。以N=5为例,N!+2,N!+3,N!+4,N!+5,都是合数,但是N!+1以及N!+6都是合数,不再往两边继续举例,因此这个办法无法证明相邻素数间隔任意。

3.所有大于2的素数都可以唯一表示成两个平方数之差

证明:首先我们知道,大于2的素数都是奇数,那么我们假设这个数为2*n+1。(n+1)^2=n^2+2*n+1,而2*n+1=(n+1)^2-n^2。

唯一性:若素数p=a^2-b^2,那么p=(a+b)*(a-b),由于p是素数,那么只能是a+b=p且a-b=1。

4.当n为大于2的整数时,2^n+1和2^n-1这两个数,至少有一个是合数

证明:2^n%3!=0。分情况讨论:

若2^n%3=1,那么2^n-1%3=0,为合数。

若2^n%3=2,那么2^n+1%3=0,为合数。

5.费马小定理:如果p是素数,a是小于p的正整数,那么a^(p-1)%p=1

证明:1.如果p是素数,那么对于任意一个小于p的正整数a,有a、2a、3a、4a、......、(p-1)a,这些数分别取余p后的结果是一个1~p-1的全排列。举个例子:5是素数,3, 6, 9, 12除以5的余数分别为3, 1, 4, 2。

反证法:如果结论不成立,我们可以知道有两个小于p的数m和n使得m*a%p=n*a%p。假设m>n,我们可以构造一个

(m-n)*a%p=0,由于p是素数,只可能(m-n)%p=0或者a%p=0,但显然的是由于m-n和a都是小于p的,因此不成立。

那么由上述结论我们可以得到a*2a*......*(p-1)a%p=(p-1)!,两边同时除去(p-1)!,即可得到a^(p-1)%p=1。

下面进入素性测试部分:

由费马小定理我们可以知道:如果p是素数,a是小于p的正整数,那么a^(p-1)%p=1。

费马素性测试:如果我们反过来考虑,如果a是小于p的正整数,a^(p-1)%p=1,是否可以得到p是素数呢。

以a=2时为例,2^4%5=1,2^340%341=1,5为素数但是341=11*31。显而易见的是,如果a^(p-1)%p!=1,那么可以直接肯定p不可能为素数,而能通过这种测试的我们称之为以2为底的伪素数。

那么自然会联想到,如果用所有小于p的数去测试p的素性呢。然而数据表明,有些合数强大到可以通过所有的这种测试。前10亿个自然数中有600个之多。

Miller-Rabin素性测试:

原理:如果p是素数,x是一个小于p的正整数,若x^2%p=1,我们可以推出(x-1)(x+1)%p=0,那么x的取值只能是1或者p-1。

具体测试方法:以341为例:

A.由于2^{340} (mod) 341 = 1,我们假设341为素数,那么我们可以得到结论:2^{170}(mod)341=1或者2^{170}(mod)341=340

B.进行求证,如果满足2^{170}(mod)341=1(正确),继续按照分解的原理求证2^{85}(mod)341=1或者2^{85}(mod)341=340

如果2^{170}(mod)341=340,我们是不可以继续往下分解的,那么我们就可以判定341是以2为底的强伪素数。

C.我们发现2^{85}(mod)341=32,所以可以得到结论341并不是素数。

这种测试方法的出错概率比费马素性测试要低得多,数据表明:第一个以2为底的强伪素数为2047。第一个以2和3为底的强伪素数则大到1373653。

具体代码(核心部分):

#include <iostream>
using namespace std ;
typedef long long ll;

ll pow_mod(ll a,ll x,ll n){//快速幂取模
    ll r=1;
    while(x){
        if(x&1){
            r=r*a%n;
        }
        a=a*a%n;
        x>>=1;
    }
    return r;
}

bool test(ll a,ll x,ll n){//a^x%n  x=n-1
    if(!(n&1))return false;//大于2的偶数不可能是素数
    while(!(x&1))x>>=1;//将x的所有2全部提取
    ll res=pow_mod(a,x,n);
    while(x!=n-1&&res!=n-1&&res!=1){
        res=res*res%n;
        x<<=1;
    }//3*3%5==4  
    return res==n-1||(x&1)==1;
    //从小求到大可以减少运算
    //如果说res==1,并且n要为素数,那么必须在x还为奇数也就是第一次进行素性判断的时候,res==1才行
    //由梅氏素性测试的原理,若t*t%n==1,则t==1或t==n-1
    //梅氏素性测试要求如果t*t%n=1的时候  才能去判定是否由t==1或者t==n-1
    //如果遇到了t*t%n=n-1的情况,此时是无法向下继续判断的,因此按照素性测试的要求,我们直接返回是强伪素数即可
    //t%n=n-1时,t*t%n=1,往后都是1
    //代码是从小判到大的,强伪素数要求要么一开始t就是1要么t在变换中途变成了n-1
}

bool isPrime(ll n){
    int a[]={2,3,5,7};
    for(int i=0;i<=3;i++){
        if(n==a[i])return true;
        if(!test(a[i],n-1,n))return false;//未通过以2 3 5 7四个数中任意一个为底时的素性测试
    }
    return true;
}

int main(){
    ll ans;
    cin>>ans;
    cout<<(isPrime(ans)?"Yes":"No");
}

防溢出的处理(利用快速乘法,加直接相乘变为利用二进制的加法):

举个例子:3*6

A.将6转换为二进制110

B.那么我们可以按照二进制对结果进行分解:3*6=3*2^{2}+3*2^{1}

C.加法的过程中取模就可以防止溢出

先对快速幂的部分做如下调整:

ll mul_mod(ll a,ll b,ll n){
    ll r=0;
    while(b){
        if(b&1){
            r=(r+a)%n;    
        }
        a=(a+a)%n;
        b>>=1;
    }
    return r;    
}

ll pow_mod(ll a,ll x,ll n){//快速幂取模
    ll r=1;
    while(x){
        if(x&1){
            r=mul_mod(r,a,n);
        }
        a=mul_mod(a,a,n);
        x>>=1;
    }
    return r;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Miller-Rabin素性测试算法是一种用于判断一个数是否为质数的算法。该算法于费马小定理,使用随机数进行迭代运算,可以高效地判断一个数是否为质数。 具体来说,该算法将要判断的数记作n,随机选取一个小于n的正整数a,将a与n进行求模运算得到b。如果b等于0或者b等于n-1,则继续选择下一个a。否则,将b平方并对n取模,得到c。如果c等于1或者c等于n-1,则继续选择下一个a。否则,不断平方c并对n取模,直到c等于1或者迭代次数达到了一定阈值。如果c等于1,则n可能是一个合数;如果迭代过程中出现了c等于n-1的情况,则n很可能是一个质数。 为了提高判断的准确性,Miller-Rabin算法会进行多次随机迭代,每次选取不同的随机数a。随机迭代次数越多,判断结果的准确性越高,但计算时间也越长。 总之,Miller-Rabin素性测试算法是一种高效、准确的判断一个数是否为质数的算法,被广泛应用于密码学、计算机科学等领域。 ### 回答2: Miller-Rabin素性测试算法是一种用于判断一个数是否为素数的快速算法。该算法于费马小定理,利用随机数的特性来判断一个数是否为素数。该算法的优势在于速度快且准确率高,同时能够应对大整数的素性测试。 该算法的具体步骤如下: 1. 首先确定待测试的数n,如果n为偶数,则直接判断n是否等于2,如果是则n为素数,因为2是最小的质数。 2. 若n为奇数,则写成n-1=2^r * d的形式,其中r为非负整数,d为奇数。 3. 接着随机选取一个整数a,且1 < a < n-1。计算a^d mod n,如果结果等于1或n-1,则可以认为n有很大的可能是素数,结束测试。 4. 若结果不等于1或n-1,则重复计算a^(2^j*d) mod n,直到出现下面两种情况之一:结果为1,或者出现了j=0,1,...,r-1时,结果为n-1。 5. 如果满足上述两种情况之一,则认为n有很大的可能是素数,结束测试。否则,重新随机选取一个a,重复上述操作进行测试。 需要说明的是,该算法的准确率可以通过多次测试进行提高。一般来说,重复进行10~20次检验,即可认为检验结果是正确的。 总之,Miller-Rabin素性测试算法是一种简单高效的素数测试算法,可以广泛应用于需要高精度计算的场合。它在加密、密码学等领域中,有着重要的应用价值。 ### 回答3: Miller-Rabin素性测试算法是一种用于判断一个数是否为素数的算法,名字来源于两位发明者:Gary L. Miller和Michael O. Rabin。与其它素数检测算法不同,Miller-Rabin素性测试算法有极高的概率能够正确地识别素数,其准确率可以达到误判的可能性小于$\frac{1}{4}$。 Miller-Rabin素性测试算法的本原理是利用了费马小定理和欧拉判别法,即对于一个素数$p$和$a<p$,有$a^{p-1} \equiv 1 \pmod{p}$,而对于合数$n=pq$,其中$p,q$为大于1的素数,则在模n下,$a^{n-1} \equiv 1 \pmod{n}$,并且除了一些“小概率事件”外,$a^{(n-1)/2} \equiv \pm 1 \pmod{n}$。 Miller-Rabin 素性测试算法的流程如下: 1.将$n-1$分解成$2^sd$的形式,其中$d$是奇数。 2.对于给定的$a<n$,利用费马小定理,计算$a^d \pmod{n}$。 3.如果$a^d \equiv 1 \pmod{n}$,则认为$n$可能是一个素数,算法结束。 4.对于$0\leq r \leq s-1$,如果$a^{2^rd} \equiv -1 \pmod{n}$,则认为$n$可能是一个素数,算法结束。 5.如果$a^{2^sd} \not \equiv 1 \pmod{n}$或$a^{2^{r}d} \not \equiv -1 \pmod{n}$(其中$0\leq r \leq s-1$),则认为$n$不是素数,算法结束。 通过多次进行以上的步骤,可以提高算法的准确率。 Miller-Rabin素性测试算法是一种在计算机领域经常使用的算法,其特点是计算量较小、正确率较高、可扩展性好。在计算机安全领域,该算法被广泛地应用于RSA算法中,用于加密和解密数据。虽然该算法在某些情况下会出现一定的偏差,但是通过多次计算,可以达到一个非常高的准确率。因此,在实际应用中,Miller-Rabin素性测试算法是一个非常实用的工具。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值