首先 介绍一下费马小定理
定义:假如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 - 1时 p * (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;
}