其他分享
首页 > 其他分享> > Miller-Rabin

Miller-Rabin

作者:互联网

算法简介

Miller-Rabin 算法可以较快地判断一个数是不是质数。
但是,这个算法是概率性算法,即有一定的概率会误判。
所以,一般会使用较多的数检验,从而降低误判的概率。

前置定理

费马小定理:\(a^{p-1} \equiv 1 (mod\ p)\)
注意:费马小定理的逆命题并不一定成立。
二次探测定理:若 \(p\) 为奇素数且 \(x^2 \equiv 1 (mod\ p)\) , 则 \(x \equiv 1 (mod\ p)\) 或 \(x \equiv p-1 (mod\ p)\)

前置算法

快速乘,快速幂

判断过程

设现在用于判断的质数为 \(p\) , 在判断的数为 \(x\) 。
首先,若 \(x=p\) ,则 \(x\) 为质数;若 \(x\) 是 \(p\) 的倍数,则 \(x\) 为合数。
然后,根据费马小定理,若 \(p^{x-1} \% x \neq 1\) , 则 \(x\) 必然是合数。
因为费马小定理的逆命题并不一定成立,所以,现在还并不能确定 \(x\) 就是质数。
接下来,令 \(k=x-1\) 。
1.令 \(k=\frac{k}{2}\) , 设 \(t=p^k \% x\) 。
2.若 \(t \neq 1\) 且 \(t \neq p-1\) ,又因为 \(p^{2k} \% x=1\) ,根据二次探测定理, \(x\) 为合数。
3.若 \(t=p-1\) 或 \(k\) 是奇数,无法继续判断,所以判断 \(x\) 为质数。否则,返回第一步,继续判断。
将多个质数的判断结果合并在一起,即可得到一个正确率极高的结果。

code

#include<iostream>
#include<cstdio>
#define int long long
using namespace std;
const int P[]={2,3,5,7,11,13,17,19,23,29};
int MUL(int a,int b,int p) //a*b%p
{
	if(!b) return 0;
	if(b==1) return a;
	int sum=MUL(a,b/2,p);
	if(b%2) return ((sum+sum)%p+a)%p;
	return (sum+sum)%p;
}
int POW(int a,int b,int p) //a^b%p
{
	if(!b) return 1;
	if(b==1) return a;
	int sum=POW(a,b/2,p);
	if(b%2) return MUL(MUL(sum,sum,p),a,p);
	return MUL(sum,sum,p);
}
bool check(int x)
{
	if(x==0||x==1) return false;
	if(x==2) return true;
	for(int i=0;i<10&&P[i]<=x;i++)
	{
		if(x==P[i]) return true;
		if(x%P[i]==0) return false;
		if(POW(P[i],x-1,x)!=1) return false;
		int k=x-1,t=0;
		if(k%2) continue;
		k/=2,t=POW(P[i],k,x);
		if(t==x-1||k%2) continue;
		while(1)
		{
			k/=2,t=POW(P[i],k,x);
			if(t!=1&&t!=x-1) return false;
			if(t==x-1||k%2) break;
		}
	}
	return true;
}
int x;
signed main()
{
	scanf("%lld",&x);
	puts(check(x)?"YES":"NO");
	return 0;
}

一些提醒

此算法的时间复杂度为 \(O(k \log^3 n)\) (其中, \(k\) 为用于判断的质数个数),在数据较大时非常优秀。
但是,在数据比较小的时候此算法的效率和 \(O(\sqrt{n})\) 的暴力都差很多。所以,在数据小时要慎用。
同时,在乘法不会爆 \(long\ long\) 时最好把快速乘去掉,可以把复杂度降为 \(O(k \log^2 n)\) 。

标签:return,int,Miller,sum,算法,MUL,质数,Rabin
来源: https://www.cnblogs.com/zhs1/p/14043999.html