Miller_Rabin算法 素数判定

本文介绍Miller-Rabin算法,一种高效的素数检测方法。该算法基于Fermat定理,通过多次随机试验判断一个数是否为素数,适用于大整数检测场景。

 

算法理论基础

       Miller-Rabin算法是Fermat算法的一个变形改进,它的理论基础是由Fermat定理引申而来。

 

  Fermat 定理: n是一个奇素数,a是任何整数(1≤ a≤n-1) ,则 a^(n-1)≡1(mod n)。

 

  Miller-Rabin 算法的理论基础:如果n是一个奇素数, 将n-1表示成2^s*r的形式(r是奇 数),a 是和n互素的任何整数, 那么a^r≡1(mod n) 或者对某个j(0≤j ≤s -1, j∈Z) 等式 a^(2^j*r) ≡-1(mod n)成立。 这个理论是通过一个事实经由Fermat定理推导而来: n是一个奇素数,则方程x^2 ≡ 1 mod n只有±1两个解。

重复n次实验。对于每一次实验,随机取检验算子a,带入定理进行检验,看看在算子a下,n能否满足

 

a^r ≡ 1 mod n或者对某个j (0 ≤ j≤ s−1, j∈Z) 等式a^(2jr) ≡ −1 mod n       **

如果任意一次实验不满足,则判定不是素数,如果都满足,可近似可以认为是素数(错误率极小)。

 

取模运算性质

术语:

For a positive integer n, two integers a and b are said to be congruent modulo n, and written as

一些有用的性质(可证明):

如果a≡b(mod m),x≡y(mod m),则a+x≡b+y(mod m)。

如果a≡b(mod m),x≡y(mod m),则ax≡by(mod m)。

如果ac≡bc(mod m),且c和m互质,则a≡b(mod m) (就是说同余式两边可以同时除以一个和模数互质的数)。

#include <iostream> 
#include <algorithm>  
#include <cstring>  
#include <map> 
using namespace std;

typedef unsigned long long ll;//10^20 左右再大我也很无奈=.= 
const int times = 10;//一般10就够了
int prime[] = {2, 3, 5, 7, 13, 17, 11, 61, 97, 24251, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 67, 71, 73, 79, 83, 89};		//得到随机检验算子 a

ll  Random(ll n){
	return (double(rand())/RAND_MAX * n+0.5);
}

ll q_mul(ll a, ll b, ll mod){
	ll ans=0;
	while(b){
		if(b & 1)	ans=(ans+a)%mod;
		a=(a<<1)%mod;
		b>>=1;
	}
	return ans;
//	return (a*b)%mod;//超时就换成这个 
}

ll q_pow(ll a, ll b, ll mod){
	ll ans=1;
	while(b){
		if(b & 1)	ans=q_mul(ans,a,mod);
		a=q_mul(a,a,mod);
		b>>=1;
	}
	return ans;
}

bool miller_rabin(ll n){				 //检验n是否是素数
	if(n<2) return false;
	if(n==2) return true;
	if(!(n&1)) return false;				//如果是2则是素数,如果<2或者是>2的偶数则不是素数
	
	ll k,j=0, x, tem = n-1;
	while(!(tem & 1)) tem>>=1,j++;
	for(int i=0;i<times;i++){				//做times次随机检验
		if(prime[i] >= n) return true;
		x = q_pow(prime[i], tem, n);				//得到a^r mod n
		if( x == 1 ) continue;			//余数为1则为素数
		for(k=0;k<j;k++){		
			if(x == n-1) break;			//否则试验条件2看是否有满足的 j
			x = q_mul(x, x, n);
		}
		if(k == j) return false;
	}
	return true;
}

int main( )
{
	long long tar;
	while(scanf("%lld",&tar)){
		if(miller_rabin( tar ))	//检验tar是不是素数
			cout << "Yes, Prime!" << endl;
		else
			cout << "No, not prime.." << endl;
	}
	return 0;
}

再大就要手动实现大整数了。。。太麻烦了,可以用java里的BigInteger,里面提供了一个实现这个算法的方法,方法原型是:

boolean isProbablePrime(int certainty)

 

参考:https://blog.youkuaiyun.com/maxichu/article/details/45458569点击打开链接

https://blog.youkuaiyun.com/chensilly8888/article/details/42834697

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值