Miller Rabin算法

首先 介绍一下费马小定理
定义:假如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=4
3,6,9 分别除以 4 得:3 2 1

反证法证明:
假设存在正整数n,m 满足0<n<m<p 且 na%p == ma%p
na%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

//偷懒用java
import 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值