普通的素数判断法
当我们要判断一个数字是否是素数的时候,往往会直接看这个数字模1到这个数字的根号,看有没有等于零的,从而判断这个数字是不是素数,这样做的时间复杂度为O(sqrt(n))
bool isPrime(int num)
{
if(num <= 1)
return false;
for(int i = 2; i * i <= num; ++i)
{
if(num % i == 0)
return false;
}
return true;
}
线性筛法求素数
线性筛法,时间复杂度为O(n)
原理在这里:https://blog.csdn.net/bjrxyz/article/details/8125913
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn = 2e5 + 5;
ll prime[maxn];
ll cnt = 0;
bool not_prime[maxn] = {1, 1};//0 和 1不是素数
void init()
{
for(ll i = 2; i < maxn; ++i)
{
if(!not_prime[i])
prime[cnt++] = i;
for(ll j = 0; j < cnt && i * prime[j] < n; ++j)
{
not_prime[i * prime[j]] = 1;
if(!(i % prime[j]))
break;
}
}
}
int main()
{
init();
return 0;
}
二次筛法求素数[L,R]
当我们的素数很大很大,但区间跨度不大时。
bool Prime[50010]; //存50000内素数判断结果
int Primer[1000010]; //存放区间[L,R]之间的素数
bool Prime1[1000010]; //判断区间[L,R]中的数是否为素数
int IsPrime()//第一次筛50000内的素数
{
int num = 0;
for(int i = 2; i <= 50000; i++)
Prime[i] = true;
for(int i = 2; i <= 50000; i++)
{
if(Prime[i])
{
Primer[num++] = i;
for(int j = i+i; j <= 50000; j+=i)
Prime[j] = false;
}
}
return num; //num为50000范围内的素数个数
}
int IsPrime2(__int64 a,__int64 b)
/*
在第一次筛素数的基础上,利用50000以内的素数,筛去范围【a,b】之间的素数倍数,
剩下则为素数
*/
{
int num = IsPrime();
memset(Prime1,true,sizeof(Prime1));
//Prime1数组用来存放范围【a,b】的素性判断
if(a == 1) //这里注意1不是素数
Prime1[0] = 0; //这里表示0+1不为素数
for(__int64 i = 0; i < num && Primer[i] * Primer[i] <= b; i++)
{
__int64 begin = a/Primer[i] + (a%Primer[i] != 0);
//上边的a/Primer算出应a为素数Primer[i]的多少倍
//(a%Primer[i]!=0)表示应从Primer[i]的a/Primer[i]倍开始筛,还是a/Primer[i]+1倍筛
if(begin == 1)//若得出结果为所被筛素数的1倍,则从该素数的2倍开始筛
begin++;
for(begin = begin*Primer[i]; begin <= b; begin += Primer[i])
Prime1[begin - a] = false;
}
//这里重新利用Primer数组,用来存放区间【a,b】间的素数,num为素数个数
memset(Primer,0,sizeof(Primer));
num = 0;
for(__int64 i = a; i <= b; i++)
if(Prime1[i-a]==1)
Primer[num++] = i-a;
return num; //num为区间[a,b]的素数个数
}
米勒拉宾素性检验
如果区间跨度很大,例如在1e14到1e18,用筛法求素数时数组开不了那么大。
所以我们改用米勒拉宾算法对素数进行检验。米勒拉宾素性测试算法是概率算法,不是确定算法。但是判断错误的概率非常非常小,速度又很快。
#include<iostream>
#include<cstdlib>
#include<ctime>
#include<cmath>
using namespace std;
bool Miller_Rabin(long long n)
{
if(n < 2)
return false;
else if(n == 2)
return true;
long long q = 0, m = n - 1;
while(m % 2 == 0) { //当m为偶数时
m >>= 1;//除2
++q; //计数
}
long long a = rand()%(n - 2) + 2;
long long x1 = (long long)pow(a, m) % n, x2;
for(int i = 1; i <= q; ++i) {
x2 = (x1 * x1) % n;
if(x2 == 1 && x1 != 1 && x1 != n - 1)
return false;
x1 = x2;
}
if(x2 != 1)
return false;
else
return true;
}
int main(void)
{
srand((unsigned)time(NULL));
long long num;
while(cin >> num) {
if(num > 1) {
if(Miller_Rabin(num))
cout << "true" << endl;
else
cout << "false" << endl;
}
}
return 0;
}
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long LL;
LL mulmod( LL a, LL b , LL p )
{
LL d = 1;
a = a % p;
while( b > 0 )
{
if(b & 1)
d = (d * a) % p;
a = (a * a) % p;
b >>= 1;
}
return d;
}
bool witness( LL a,LL n)
{
LL d = n - 1 ;
if( n == 2 )
return true ;
if( !(n & 1) )
return false ;
while(!(d & 1))
d = d / 2;
LL t = mulmod(a, d, n);
while((d != n - 1) && (t != 1) && (t != n - 1))
{
t = mulmod( t, 2, n);
d = d << 1;
}
return (t == n - 1) || (d & 1);
}
bool isprime( LL n)
{
int a[3] = {2, 7, 61};
for(int i = 0; i < 3; i++)
if(!witness(a[i], n))
return false;
return true;
}
int main()
{
LL s;
cin >> s;
if(isprime(s))
cout << "YES";
else
cout << "NO";
return 0;
}
参考来源
博客
https://blog.csdn.net/lianai911/article/details/45056957
博客
https://blog.csdn.net/bjrxyz/article/details/8125913
博客
https://www.cnblogs.com/KyleDeng/p/9244850.html