当前位置: 首页 > news >正文

判断一个数是否是质数

判断一个数是否是质数。

方法1.

在大于 1 的自然数中,如果 num 有除了 1 和自身以外的因数,说明 num 不是质数,返回 0。

最简单的方法是 i 从 2 到 num-1 都试一遍,看是否能整除 num。

  • 若 i 能整除 num,则 num 不是质数,返回 0.
  • 若循环结束,没找到能整除 num 的 i,则 num 是质数,返回 1.

设 num 为合数,有 num = i * j。若 i > √num,推出 j 的取值范围。

i = num/j > √num
num > √num * j
等式两边同时除以 √num:√num > j
整理得:j < √num

一个因数 i > √num,则另一个因数 j < √num。在 [2, √num] 范围内,必有一整数能整除 num。换言之,如果遍历到 i > √num 时,未能有 i 能整除 num,则 num 为质数。

所以 i 没必要从 2 到 num-1,到 √num 就行。

例 53,√53 ≈ 7.28,当循环到 i = 8 时,假设 53 为合数,53 = 8 * j,8 > √53,所以 j < √53,j <= 7,而在之前的遍历中 i = 2、i = 3、… i = 7 并没有出现 num % i == 0 的情况,否则循环直接终止,所以没有这样的 j 能整除 num。

i <= √num
等式两边平方得:i * i <= num
考虑到 i * i 容易溢出,转为:i <= num/i
int isPrime(int num) {
    if (num <= 1) {
		return 0;
	}
    for (int i = 2; i <= num / i; i++) {
        // 若 i 能整除 num,则 i 是 num 的因数,所以 num 不是质数,循环终止
        if (num % i == 0) {
            return 0;
        }
    }
    return 1;
}

方法1算 1 亿以内(包括 1 亿)的质数个数有些困难。

方法2.

创建数组 primeArr,下标为 num。

  • primeArr[num] 为 0,代表 num 是质数。
  • primeArr[num] 为 1,代表 num 是合数。
  • primeArr[num] 为 -1,代表 num 既不是合数也不是质数。

num 为质数时,则 num 的倍数即 num * k 为合数,则 primeArr[num * k] = 1,k 从 2 到 (length-1)/num。

但请看:

2:4, 6, 8, 10...
3:6, 9, 12, 15...
5:10, 15, 20, 25...

第一轮循环 primeArr[2] = 0、primeArr[4] = 1、primeArr[6] = 1…

第二轮循环 primeArr[3] = 0、primeArr[6] = 1、primeArr[9] = 1…

primeArr[6] 重复设置。

primeArr[3 * 2] 已在 primeArr[2 * 3] 时被设置为 1。

primeArr[4 * 2] 已在 primeArr[2 * 4] 时被设置为 1;primeArr[4 * 3] 已在 primeArr[3 * 4] 时设置为 1…

综上,k ∈ [2, num-1] 已经在之前的循环中被设置,不妨令 k 从 num 开始。

2:4, 6, 8, 10...
3:9, 12, 15, 18...
5:25, 30, 35, 40...
#include <stdio.h>

#define MAX_LENG 100000
static int primeArr[MAX_LENG];
static int isInit = 0;

int primeInit() {
    int primeCount = 0;
    primeArr[0] = primeArr[1] = -1;
    
    for (int num = 2; num < MAX_LENG; num++) {
        if (primeArr[num] == 0) {
            primeCount++;
            // 怕 k * num 溢出
            for (int k = num; k < (MAX_LENG) / (num+0.0); k++) {
                primeArr[num * k] = 1;
            }
            // 或者使用 i += num,i 为 num 的倍数
            /*
            	for (int i = num * num; i < MAX_LENG; i += num) {
            		primeArr[i] = 1;
            	}
            */
        }
    }
    isInit = 1;
    return primeCount;
}
int isPrime(int num) {
    if (num >= MAX_LENG) {
        printf("只支持 [0, %d] 范围内的查询\n", MAX_LENG-1);
        return 0;
    }
    if (!isInit) {
        int primeCount = primeInit();
        printf("[0, %d] 范围内的质数个数:%d\n", MAX_LENG-1, primeCount);
    }
    return primeArr[num] == 0 ? 1 : 0;
}

方法3.

方法 2 中也有很多数被重复设置,如

  • 12:2 * 6、3 * 4 重复设置。
  • 18:2 * 9、3 * 6 重复设置。
  • 24:2 * 12、3 * 8 重复设置。
  • 45:5 * 9、3 * 15 重复设置。

所以考虑换个方案。

让 k 从 2 到 num。k >= num+1 的部分交给下几轮循环,如 num = 4,k = 5 可以交给 num = 5,k = 4。

2:4
3:6,9
4:8,12,16
5:10,15,20,25
6:12,18,24,30,26
7:14,21,28,35,42,49
8:16,24,32,40,48,56,64
9:18,27,36,45,54,63,72,81

注意看,第 3 行、第 5 行的 12 重复。

num % k == 0
设 num / k = n
那么 num * (k+1) = n*k * (k+1)
num * (k+1) 在循环的 num = n*(k+1) 时重复设置

类似的 num * (k+2) = n*(k+2) * k 重复设置

这意味当 k 能整除 num 时,k 没必要++,num * (k+?) 会在之后的循环中被设置,本次循环到此终止。

例 num = 9,k = 3 时,9 % 3 == 0,9 * 4 = 3 * 3 * 4 = 12 * 3,36 被 9 * 4 和 12 * 3 重复设置。

例 当 num 为偶数,k = 2 时,num % k == 0,则 k 到此终止,没必要++。如 num = 4,k = 2,k = 3、k = 4… 留给 num = 6、num = 8… 设置。

2:4
3:6,9
4:8
5:10,15,20,25
6:12
7:14,21,28,35,42,49
8:16
9:18,27
10:20
11:22,33,44,55,66,77,88,99,110,121
12:24
13:26,39,52,65,78,91,104,117,130,143,156,169

注意,第 10 行的 44 = 11 * 4 = 11 * 2 * 2 = 22 * 2。

由于合数 4 可以分解为多个质数的乘积,所以在 num = 22,k = 2 时,也重复设置了。需要规定 k 必须为质数,即 k = 2、3、5、7、11、13、17…

24
369
48
5101525
612
714213549
816
91827
1020
1122335577121
1224
1326396591143169
#include <stdio.h>

#define MAX_LENG 1000000
static int primeArr[MAX_LENG];
static int isInit = 0;

int primeInit() {
    primeArr[0] = primeArr[1] = -1;
	int primeCount = 0;

    for (int num = 2; num < MAX_LENG; num++) {
		if (primeArr[num] == 0) {
			primeCount++;
		}
		// k ∈ [2, num]
        // 第2个条件可以修改为 k < (MAX_LENG) / (num+0.0)
        for (int k = 2; k <= num && k*num < MAX_LENG; k++) {
			// k 必须为质数
            if (primeArr[k] == 0) {
            	primeArr[num * k] = 1;
				// 若 num % k == 0,设 num = n * k
				// num *(k+1)、num *(k+2)... 留给 num = n*(k+1)、n*(k+2)...时设置
            	if (num % k == 0) break;
            }
        }
    }
    isInit = 1;
	return primeCount;
}
int isPrime(int num) {
    if (num >= MAX_LENG) {
        printf("只支持 [0, %d] 范围内的查询\n", MAX_LENG-1);
        return 0;
    }
    if (!isInit) {
        int primeCount = primeInit();
		printf("[0, %d] 范围内的质数个数:%d\n", MAX_LENG-1, primeCount);
    }
    return primeArr[num] == 0 ? 1 : 0;
}
10以内的质数个数:4
100以内的质数个数:25
1000以内的质数个数:168
10000以内的质数个数:1229
100000以内的质数个数:9592
1000000以内的质数个数:78498
10000000以内的质数个数:664579
100000000以内的质数个数:5761455
1000000000以内的质数个数:50847534

相关文章:

  • 诊断Android系统原生代码Native崩溃问题
  • React中实现一键复制——五种办法
  • byName自动装配和byType自动装配
  • 【黑马Java笔记汇总】JavaSE+JavaWeb+SSM+Springboot笔记汇总
  • DRF 用户认证
  • 系统架构演变历史及集群、分布式、微服务、SOA的概念区别
  • 四、RocketMq本地集群搭建
  • 金仓数据库 KingbaseES 插件参考手册 xml2
  • FITC-PEG-SH/Fluorescent-PEG-SH 多种分子量可选/荧光素聚乙二醇巯基 FITC-PEG-SH
  • 常用hooks用法总结
  • 赛默飞世尔Thermo Fisher仪器电路板维修故障概述
  • 对于生物素-PEG32-NHS 酯,Biotin-PEG32-NHS ester物理性质大家了解多少了?
  • 关于神经网络的正确说法,神经网络通俗的解释是
  • python带你采集桌游、剧本杀游戏店数据信息~
  • sd卡数据丢失的原因有哪些?常见的sd卡数据丢失原因及恢复方法
  • [笔记] php常见简单功能及函数
  • [分享]iOS开发-关于在xcode中引用文件夹右边出现问号的解决办法
  • C++入门教程(10):for 语句
  • JavaScript 事件——“事件类型”中“HTML5事件”的注意要点
  • javascript 总结(常用工具类的封装)
  • Java知识点总结(JDBC-连接步骤及CRUD)
  • js
  • leetcode讲解--894. All Possible Full Binary Trees
  • Redash本地开发环境搭建
  • 阿里中间件开源组件:Sentinel 0.2.0正式发布
  • 对象管理器(defineProperty)学习笔记
  • 诡异!React stopPropagation失灵
  • 使用iElevator.js模拟segmentfault的文章标题导航
  • 一个项目push到多个远程Git仓库
  • 在Mac OS X上安装 Ruby运行环境
  • 【云吞铺子】性能抖动剖析(二)
  • HanLP分词命名实体提取详解
  • puppet连载22:define用法
  • 如何正确理解,内页权重高于首页?
  • ​HTTP与HTTPS:网络通信的安全卫士
  • #微信小程序(布局、渲染层基础知识)
  • (搬运以学习)flask 上下文的实现
  • (附源码)node.js知识分享网站 毕业设计 202038
  • (附源码)springboot太原学院贫困生申请管理系统 毕业设计 101517
  • (过滤器)Filter和(监听器)listener
  • (含react-draggable库以及相关BUG如何解决)固定在左上方某盒子内(如按钮)添加可拖动功能,使用react hook语法实现
  • (介绍与使用)物联网NodeMCUESP8266(ESP-12F)连接新版onenet mqtt协议实现上传数据(温湿度)和下发指令(控制LED灯)
  • *ST京蓝入股力合节能 着力绿色智慧城市服务
  • ./configure,make,make install的作用
  • .helper勒索病毒的最新威胁:如何恢复您的数据?
  • .net core 6 redis操作类
  • .Net FrameWork总结
  • .net 程序 换成 java,NET程序员如何转行为J2EE之java基础上(9)
  • .Net8 Blazor 尝鲜
  • .NET开源的一个小而快并且功能强大的 Windows 动态桌面软件 - DreamScene2
  • .net实现客户区延伸至至非客户区
  • .net中调用windows performance记录性能信息
  • .secret勒索病毒数据恢复|金蝶、用友、管家婆、OA、速达、ERP等软件数据库恢复
  • @cacheable 是否缓存成功_让我们来学习学习SpringCache分布式缓存,为什么用?
  • [ CTF ] WriteUp-2022年春秋杯网络安全联赛-冬季赛