Miller Rabin算法

来源:互联网 发布:c语言中short什么意思 编辑:程序博客网 时间:2024/06/07 20:19

首先 介绍一下费马小定理
定义:假如p是质数,且gcd(a,p)=1,那么 a^(p-1)≡1(mod p)
当p为素数 a^(p-1) = 1 (mod p) 一定成立
当a^(p-1) = 1 (mod p)成立时 p很可能为素数
所以可以用作素数测试(但不一定准确)

证明费马小定理前 先证明:a,2a,3a,....,(p-1)a分别除以p    余数将得到1,2,3....,(p-1)例如a=3 p=43,6,9 分别除以 4 得:3 2 1反证法证明:假设存在正整数n,m 满足0<n<m<p 且 na%p == ma%pna%p = ma%p    -->   ma%p - na%p = 0                -->  a(m-n)%p = 0因为m-n>=1 且 (m-n)<p 且 a<p所以a(m-n)不可能含有因子p 与 a(m-n)%p = 0 矛盾 -->假设不成立所以:a%p * 2a%p * .... * (p-1)a%p = (p-1)!    (p-1)!*a^(p-1) = (p-1)!   (mod p)消去2边的(p-1)!得:  a^(p-1) = 1  (mod p)

后来 Miller和Rabin根据以下定理 对基于费马小定理的素数测试进行改进 使得准确率大大提高
对小于素数 p 的正整数 x 有: 当 x^2 = 1 (mod p) 时 x = 1或p - 1

证明:因为:x^2-1 = (x + 1)*(x - 1)  --> (x + 1)*(x - 1) % p = 0因为x < p p为素数所以只有当x = 1时 : 2*0%p = 0或 当 x = p - 1p * (p - 2) % p = 0

Miller-Rabin:

如果 a^(p-1) = 1 (mod p)因为大于2的素数p都是奇数 p-1都是偶数所以 p - 1可以表示为 d*2^r  r为(p-1)中2的因子个数-->  a^(d*2^r) = 1 (mod p)令x = a^(d*2^(r-1))则 x^2 = 1 (mod p)x%p = 1或p-1显然 对x[i] = a^(d*2^(r-i)) i<=r都成立Ps: x[i] = x[i+1]^2---------先检验a^(p-1) = 1 (mod p)是否成立①成立:令x[i] = a^(d*2^(r-i))  i<=r如果x[i]%p 不等于1或p-1 p一定不是素数如果x[i]%p = 1 即:x[i+1]^2 = 1(mod p) 继续检查 x[i+1]%p如果x[i]%p = p-1或检查完所有x[i] 则p很可能为素数②不成立:p一定不是素数

例题:
51NOD 1186 质数检测 V2
nefu 120 梅森素数


质数检测V2

//偷懒用javaimport java.io.BufferedInputStream;import java.math.BigInteger;import java.util.Random;import java.util.Scanner;public class Main {    final static BigInteger two = BigInteger.valueOf(2);    static boolean witness(BigInteger a,BigInteger n){//合数返回true 素数false        BigInteger m = n.subtract(BigInteger.ONE);//m=n-1        int j=0;        while(m.mod(two).intValue()==0){//n-1 = m*(2^j)            ++j;            m = m.divide(two);        }        BigInteger x = a.modPow(m,n);//x=a^m (mod n)        if(x.compareTo(BigInteger.ONE)==0||x.compareTo(n.subtract(BigInteger.ONE))==0)            return false;        while(j-->0){            x = x.multiply(x).mod(n);            if(x.compareTo(n.subtract(BigInteger.ONE))==0)                return false;        }        return true;    }    static boolean Miller_Rabin(BigInteger n){        final int Times = 12;//测试12次        if(n.compareTo(two)==0)            return true;        if(n.compareTo(two)<=-1||n.mod(two).intValue()==0)            return false;        Random random = new Random();        BigInteger nSub1 = n.subtract(BigInteger.ONE);        for(int i=0;i<Times;++i){            BigInteger a = BigInteger.valueOf(random.nextInt(100) + 1);            a = nSub1.min(a);            if(witness(a,n))                return false;        }        return true;    }    public static void main(String[] args) {        Scanner scanner = new Scanner(System.in);        BigInteger n = scanner.nextBigInteger();        if(Miller_Rabin(n)){            System.out.println("Yes");        }        else{            System.out.println("No");        }    }}

梅森素数

#include<iostream>#include<stdlib.h>#include<stdio.h>#include<string>#include<vector>#include<deque>#include<queue>#include<algorithm>#include<set>#include<map>#include<stack>#include<time.h>#include<math.h>#include<list>#include<cstring>#include<fstream>//#include<memory.h>using namespace std;#define ll long long#define ull unsigned long long#define pii pair<int,int>#define INF 1000000007#define pll pair<ll,ll>#define pid pair<int,double>ll multi(ll a,ll b,ll mod){//(a*b)%mod    ll ans=0;    while(b){        if(b&1){            ans = (ans + a) % mod;        }        b >>= 1;        a = (a << 1) % mod;    }    return ans;}ll quick_mod(ll a,ll b,ll mod){    ll ans=1;    a%=mod;    while(b){        if(b&1){            ans = multi(a,ans,mod);        }        b>>=1;        a = multi(a,a,mod);    }    return ans;}bool witness(ll a,ll n){//noprime    ll m = n - 1;    int j=0;    while(0==(m&1)){//n-1 = m*(2^j)        ++j;        m>>=1;    }    ll x = quick_mod(a,m,n);//x=a^m (mod n)    if(x==1||x==n-1)        return false;    while(j--){        x = x*x%n;        if(x == n-1)            return false;    }    return true;}bool Miller_Rabin(ll n){    const int Times = 12;    if(n==2)        return true;    if(n<2||n%2==0)        return false;    for(int i=0;i<Times;++i){        ll a = rand()%(n-1) + 1;        if(witness(a,n))            return false;    }    return true;}int main(){    //freopen("/home/lu/文档/r.txt","r",stdin);    //freopen("/home/lu/文档/w.txt","w",stdout);    int T,p;    ll x;    scanf("%d",&T);    while(T--){        scanf("%d",&p);        ll n = (ll)1<<p;        puts(Miller_Rabin(n-1)?"yes":"no");    }    return 0;}

0 0
原创粉丝点击