- 单个素数最基本的判定方法
bool check(int i)
{
int k=sqrt(i);
for(int j=2;j<=k;j++)
if(i%j==0)return false;
return true;
}
- 单个素数的判定(6的倍数相邻法)
#include <stdio.h>
#include <math.h>///floor函数的头文件
int isPrime(int n)
{ //返回1表示判断为质数,0为非质数,在此没有进行输入异常检测
float n_sqrt;
if(n==2 || n==3) return 1; ///与floor函数对应的是ceil 函数,即上取整函数。
if(n%6!=1 && n%6!=5||n==1) return 0;//不在6的倍数两侧的一定不是质数
n_sqrt=floor(sqrt((float)n)); ///floor(x),也写做Floor(x),其功能是“向下取整”,
///或者说“向下舍入”,即取不大于x的最大整数(与“四舍
for(int i=5;i<=n_sqrt;i+=6)//在6的倍数两侧的也可能不是质数
{ ///五入”不同,下取整是直接取按照数轴上最接近要求
if(n%(i)==0 | n%(i+2)==0) return 0; ///值的左边值,即不大于要求值的最大的那个值)。
}
return 1;//排除所有,剩余的是质数
}
int main()
{
int flag,x;
while(~scanf("%d",&x)){
flag=isPrime(x);
printf("%d\n",flag);
}
return 0;
}
///floor(3.14) = 3.0
///floor(9.999999) = 9.0
///floor(-3.14) = -4.0
///floor(-9.999999) = -10
- 素数普通筛
///普通筛——埃拉托斯特尼(Eratosthenes)筛法:
#include<stdio.h>
#include<math.h>
#include<stdbool.h>
#include<string.h>
///#include<bits/stdc++.h> ///或者直接万能头文件
#define N 100
int main(void)
{
bool number[N+1];
int i,j;
memset(number,true,sizeof(number)); ///memset需要#include<string.h>头文件
for(i=2;i<=sqrt(N);i++)
{
if(number[i]==true)///如果i是素数
{
for(j=2;j*i<=N;j++)
{
number[i*j]=false;///如果i是素数,则i*j不是素数
}
}
}///所有非素数都标记为false,素数都标记为true
for(i=2;i<N+1;i++)
if(number[i]==true)
printf("%d ",i);//输出所有素数
return 0;
}
///此筛选法的时间复杂度是O(nloglogn)
///算法改进:
#include<stdio.h>
#include<stdbool.h>
#include<string.h>
#include<math.h>
#define N 100
int main(void)
{
bool number[N+1];
int i,j;
memset(number,true,sizeof(number));
for(i=2;i<=sqrt(N);i++)
{
if(number[i]==true)///如果i是素数
{
for(j=i*i;j<=N;j+=i)
{
number[j]=false;///二次筛选法:i是素数,则下一个起点是i*i,把后面的所有的i*i+2*n*i筛掉
}
}
}///所有非素数都标记为false,素数都标记为true
for(i=2;i<N+1;i++)
if(number[i]==true)
printf("%d ",i);///输出所有素数
return 0;
}
- 素数普通筛(模板)
#include<stdio.h>
const int maxn = 1e7 + 5;
int pri[maxn];
void getPrime(int n) {
for (int i = 0; i <= n; ++i) pri[i] = i;
pri[1] = 0;
for (int i = 2; i <= n; ++i) {
if (!pri[i]) continue;
pri[++pri[0]] = i;
for (int j = 2; i * j <= n && j < n; ++j) {
pri[i * j] = 0;
}
}
for(int k=1;k<=n;++k){
if(pri[k]!=0){
printf("%d ",pri[k]);
}
}
}
int main()
{
int a;
while(~scanf("%d",&a))
{
getPrime(a);
}
return 0;
}
- 素数线性筛
///线性筛——欧拉Euler筛(时间复杂度为O(n))
#include<stdio.h>
#include<stdbool.h>
#include<string.h>
#define N 1000
bool number[N+1];
int prime[N+1];
int main(void)
{
int i,j,count=0;
memset(number,true,sizeof(number));///memset只能将整形数组初始化值为0或-1,其余值可用fill函数进行填充
for(i=2;i<=N;i++)
{
if(number[i])
prime[count++]=i;
for(j=0;j<count&&prime[j]*i<=N;j++)
{
number[prime[j]*i]=false;
if(i%prime[j]==0) ///精华就在于此:它保证每个合数只会被它的最小质因数筛去,因此每个数只会被标记一次,所以时间复杂度是O(n)
break;
}
}
for(i=2;i<N+1;i++)
if(number[i]==true)
printf("%d ",i);
return 0;
}
可能是求质数最高效的算法
C++代码:
/*普通筛*/
#include <iostream>
using namespace std;
int prime(int n);
int main() {
prime(100);
return 0;
}
int prime(int n){
int i;
bool *prime = new bool[n+1];
for(i=2;i<n;i++){
prime[i] = true;
}
for(i=2;i<=n;i++){
if(prime[i]){
cout<<i<<" ";
for(int j=i+i;j<n;j+=i){
prime[j] = false;
}
}
}
cout<<endl;
return 0;
}
- 素数筛法预处理模板
(预处理筛出素数、对一个数直接查询是否为素数):
/*筛选2~N范围内的素数,存进prime数组*/
#include<iostream>
using namespace std;
const int N=1e4;
int prime[N],b[N],k=1;///注意k初始化为1
void get_prime()
{
bool a[N+5];///放大一点防止数组越界
for(int i=2;i<=N;i++){
a[i]=true;
}
for(int i=2;i<=N;i++){
if(a[i]){
prime[k]=i,b[i]=k,k++;///prime数组存素数,b数组记录该素数为第几个素数
for(int j=i+i;j<=N;j+=i){
a[j]=false;
}
}
}
}
int main()
{
get_prime();//预处理,筛出素数
for(int i=1;i<k;i++){
cout<<prime[i]<<' '<<b[prime[i]]<<endl;///输出素数prime[i]和该素数为第几个素数b[prime[i]],运行结果如下图所示
}
///当判断一个数是否为素数时就可以根据b数组直接查询判断,而不需要对prime数组进行遍历查询,以下为例子
int x;
cin>>x;
if(b[x])
cout<<"it is prime"<<endl;
else
cout<<"it isn't prime"<<endl;
return 0;
}
预处理出素数,直接查询一个数x是否为素数:
const int N=1e4+5;
bool prime[N];
void get_prime()
{
for(int i=2;i<=N;i++)
prime[i]=1;
for(int i=2;i<=N;i++){
for(int j=i+i;j<=N;j+=i)
prime[j]=0;
}
}
int main()
{
get_prime();
cin>>x;
if(prime[x])cout<<"It is a prime"<<endl;
else cout<<"It isn't a prime"<<endl;
}
- 利用费马小定理进行素性测试
若n为素数,则其满足费马小定理:a^(n-1) ≡ 1(mod n)
即如果一个数n是素数,那么 a^(n-1)%n恒等于1 (a为该范围内任意数:1<=a<n)
注意:费马小定理只是素数的必要条件,而不是充分条件,即满足费马小定理的数不一定是素数。所以可通过使用随机数生成a和增加验证费马小定理的次数来提高素性判定的准确率。
题解:费马小定理 + 大数 + 快速幂
import java.math.BigInteger;
import java.util.Random;
import java.util.Scanner;
/**
* @author Hollay
* @create 2020-09-09-17:29
* @description
*/
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNext()) {
BigInteger n = sc.nextBigInteger();
BigInteger a = new BigInteger("0");
BigInteger ans = new BigInteger("1");
Random rand = new Random();
boolean flag = false;
for (int i = 0; i < 30; i++) {
do {
a = new BigInteger(128, rand);
a = a.mod(n);
} while (a.equals(BigInteger.ZERO));
ans = BigNumberFermat(a, n.subtract(BigInteger.ONE), n);
if (!ans.equals(BigInteger.ONE)) {
System.out.println("no");
flag = true;
break;
}
}
if (flag == false) {
System.out.println("yes");
}
}
sc.close();
}
static BigInteger BigNumberFermat(BigInteger a, BigInteger n, BigInteger mod) {
BigInteger ret = new BigInteger("1");
BigInteger two = new BigInteger("2");
while (!n.equals(BigInteger.ZERO)) {
if (n.mod(two) != BigInteger.ZERO) {
ret = ret.multiply(a);
ret = ret.mod(mod);
}
a = a.multiply(a);
a = a.mod(mod);
n = n.divide(two);
}
return ret;
}
}