星星之火OIer:素数判断——Miller_Rabin

本文介绍了如何判断素数,包括普通判断方法和更高效的Miller-Rabin素数测试法。Miller-Rabin算法基于费马小定理和二次探测定理,通过随机测试提高正确率,虽然存在一定的误差率,但能有效检测大整数的素性。文中给出了详细的算法流程和代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这一讲中,我们来看一下如何判断一个素数

常用的有2

目录

——普通判断

——Miller Rabin素数测试法

算法前置::

算法流程::

代码::


O(\sqrt{n})=O(n^\frac{1}{2})——普通判断

2\sqrt{n}依次判断n \% i是否等于0

代码如下::

for(int i=2;i<=int(sqrt(n));i++)
    if(n%i==0) {
        puts("Unprime");//将就看到起,我也不晓得怎么说了
        return 0;
    }
puts("Prime");

这是很简单的

O(\sqrt{\sqrt{n}})=O(n^\frac{1}{4})——Miller Rabin素数测试法

这是一个可以检测rp的算法

因为这是基于随机算法而来的素数测试法

算法前置::

  • 费马小定理:若a是整数,p是质数,且a\%p!=0,则a^{p-1}\equiv 1(\mod p),但反过来不一定成立,即如果a^{p-1}\equiv 1(\mod p)a,p互质不能退出p为质数,但这种数是极少见的
  • 二次探测定理:若p是质数,且0<x<p,则方程x^2-1\equiv 1(\mod p)的解为x=1x=p-1
  • 模运算:(a*b)\%n=(a\%n*b\%n)\%n
  • 快速幂、快速积:运用二分的思想,快速求出a^ba*b

算法流程::

  • 判断n是不是2,如果是,返回true
  • 判断n是否小于2或者n\%2==0,如果是,返回false
  • n-1=u*2^t并求出u,t,其中u是奇数
  • x=(a^u)\%n
  • 然后是t次循环,每次循环都让y=(x^2)\%n,x=y,这样t次循环之后x=a^{u*2^t}=a^{n-1}
  • 因为根据二次探测定理定理,如果x!=1||x!=n,那么n肯定不是质数,返回false
  • 然后又可以用费马小定理,若x!=1,则n也不是质数
  • 然鹅因为Miller_Rabin算法的正确率只有75\%左右,所以要循环k次,k请自取,算法错误率为\frac{1}{4^k}
  • 然后就看rp

更多详细的解释请看代码,谢谢

代码::

#include<ctime>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
#define il inline
#define rt return
#define bl bool
#define vd void
il vd read(ll &x) {
    x=0;
    ll f=1;
    char s=getchar();
    while(s<'0'||s>'9') {
        if(s=='-')
            f=-1;
        s=getchar();
    }
    while(s>='0'&&s<='9') {
        x=x*10+s-48;
        s=getchar();
    }
    x*=f;
}
il vd pr(ll x) {
    if(x<0) {
        putchar('-');
        x=-x;
    }
    if(x>9)
        pr(x/10);
    putchar(x%10+48);
}//快读快输不解释
il ll ksc(ll a,ll b,ll n) {//快速幂和快速积请看作者的另一篇博客
	ll ans=0;
	while(b) {
		if(b&1)
			ans=(ans+a)%n;
		a=(a<<1)%n;
		b>>=1;
	}
	rt ans;
}
il ll ksm(ll a,ll b,ll n) {
	ll ans=1;
	while(b) {
		if(b&1)
			ans=ksc(ans,a,n);
		a=ksc(a,a,n);
		b>>=1;
	}
	rt ans;
}
il bl miller_rabin(ll n) {//Miller_Rabin算法
	ll a,b,x,y,u,t;
	if(n==2)//看n是否为2
		rt 1;//为2就是质数
	else if(n<2||!(n&1))//小于2或是2的倍数
		rt 0;//不是质数
	for(t=0,u=n-1;!(u&1);t++,u>>=1);//求出u和t
	for(ll i=0;i<20;i++) {//这个20是可以想开多大就开多大的/*只要不超时*/
		a=rand()%(n-2)+2;//随机生成一个数
		x=ksm(a,u,n);//快速幂
		for(ll j=0;j<t;j++) {
			y=ksc(x,x,n);//快速积
			if(y==1&&x!=1&&x!=n-1)//二次探测定理
				rt 0;//不是质数
			x=y;//更新
		}
		if(x!=1)//费马小定理
			rt 0;//不是质数
	}
	rt 1;//有很大可能是质数
}
ll t,n,a;
int main() {
	srand((unsigned)time(NULL));
	read(t);
	while(t--) {
		read(n);
		if(miller_rabin(n))
			puts("YES");
		else
			puts("NO");
	}
}

大概就是这样了,有错误请指出,谢谢大家啦

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值