常规写法亲民,高效写法炼人。用素数的基本特性写,易读易懂;用6k±1特性写,高效但却得有学过《数论》。
(笔记模板由python脚本于2024年05月09日 19:47:00创建,本篇笔记适合初通Python,熟悉六大基本数据(str字符串、int整型、float浮点型、list列表、tuple元组、set集合、dict字典)的coder翻阅)
-
Python 官网:https://www.python.org/
-
Free:大咖免费“圣经”教程《 python 完全自学教程》,不仅仅是基础那么简单……
地址:https://lqpybook.readthedocs.io/
自学并不是什么神秘的东西,一个人一辈子自学的时间总是比在学校学习的时间长,没有老师的时候总是比有老师的时候多。
—— 华罗庚
- My CSDN主页、My HOT博、My Python 学习个人备忘录
- 好文力荐、 老齐教室

本文质量分:
本文地址: https://blog.csdn.net/m0_57158496/
CSDN质量分查询入口:http://www.csdn.net/qc
- ◆ 素数判定的优化
- 0、“高级”代码
- 1、最平民的写法
- 2、算法优化
- 2.1 剔除偶数
- 2.2 平方根特性
- 2.3 6k±1规则
- 2.4 素数列表
- 2.5 代码解析
- 3、结语
- 4、我关于“素数”的学习笔记
- 5、完整源码(Python)
◆ 素数判定的优化
0、“高级”代码
- ‘高效的素数判定算法’
当我读懂这段代码的时候(这是一个非法高效的算法,找出106以内的所有素数,用时不到6秒),就有些感叹了。解决“问题”的代码也和写文章的词句一样,也是要“推敲”的,在不同的语境表达不一样的“情感”。所以,有了这篇笔记。😋
1、最平民的写法
素数是一个大于1的自然数,除了1和它本身以外不再有其他因数。换句话说,如果一个数只能被1和它本身整除,那么这个数就是素数。例如,2、3、5、7、11、13、17、19、23等都是素数。
根据素数的定义可以写法判断素数的基本算法。 这是最简单直接的方法。对于给定的数n,如果n不是2,则检查从2到n的所有整数是否能整除n。如果能被整除,则n不是素数;如果都不能整除,则n是素数。
python代码
def isPrime(num: int) -> bool:''' 素数判定 '''if num < 2:return False # 小于2的都不是素数for i in range(2, num):if num%i == 0:return False # 当num有1和自身以外的因子,不是素数return True # 经过前面的排查,就只剩素数了
效率
2、算法优化
2.1 剔除偶数
除2之外,偶数都不是素数。据此特性,可以首先剔除偶数,减少试除次数而增效。
Python代码
def isPrime(num: int) -> bool:''' 素数判定 '''if num < 2:return False # 小于2的都不是素数if num == 2: return True # 2是素数elif num%2 == 0: return False # 剔除偶数for i in range(3, num, 2): # 只试除大于2的奇数if num%i == 0:return False # 当num有1和自身以外的因子,不是素数return True # 经过前面的排查,就只剩素数了
效率
减少了一半试除,增效一倍。
2.2 平方根特性
一个自然数的因子,必定不大于其平方根。因为如果自然数n有一个因子大于sqrt(n),那么必定有一个因子小于sqrt(n)。
据此,可以优化算法,提升效率。
Python代码
def isPrime(num: int) -> bool:''' 素数判定 '''if num < 2:return False # 小于2的都不是素数for i in range(2, num):if i*i > num: break # 一个数的因子,必定小于等于其平方根if num%i == 0:return False # 当num有1和自身以外的因子,不是素数return True # 经过前面的排查,就只剩素数了
效率
减少了试除的一半(当被判定的数是素数时),次数效率提升了近50倍。
2.3 6k±1规则
所有的素数除了2和3都形如6k±1的形式,其中k是非负整数。这个规则可以减少试除法中需要检查的数的数量。
Python代码
def isPrime(num: int) -> bool:''' 素数判定 '''if num < 2:return False # 小于2的都不是素数if num == 2 or num == 3: return True # 2和3都是素数elif num%2 == 0 or num%3 == 0: return False # 剔除2、3的倍数for i in range(5, int(num**0.5)+1, 6): # 只检查6k±1的自然数if num%i == 0 or num%(i+2) == 0: return False # 大于5的素数都满足6k±1的形式,6k形式的数一定是合数return True # 经过前面的排查,就只剩素数了
效率
这即是,开篇图片中的“最佳算法”。
2.4 素数列表
找出限定范围内的所有素数,如果有上限平方根以内的素数列表,+上6k±1规则,可以更高效的“运作”。如查找106以内的所有素数:
Python代码
def isPrime(num: int) -> bool:if num > 10**6-1:input(f"\n{' 本函数仅限于查找10^6以内的素数 ':~^28}")return # 退出代码执行返回命令行if num < 2:return False # 剔除2以下的数if 1 < num < 4:return Trueif num%2 == 0 or num%3 == 0:return Falsemyprimes = (5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997) # 1000以内大于5的素数,由于前面已剔除2、3的倍数,就不再试除2、3。本列表仅限于查找100w以内的素数myprimes = iter(myprimes)for i in myprimes:if i*i > num:break if num%i == 0:return Falsereturn True#isPrime(1000_000+1) # 调试报错提示
效率
由试炼可鉴,用时比6k±1规则又缩短了近1/4。
报错提示调试
2.5 代码解析
对2.3节代码的评价
1行:函数定义,接受一个整数参数num
,并返回一个布尔值。
2行:函数的文档字符串,简要描述了函数的功能。
4行:如果num
小于2,直接返回 False,因为素数定义为大于1的自然数。
6-7行:如果num
等于2或3,直接返回 True,因为2和3都是素数。
9行:如果num
是2或3的倍数,返回 False,因为这些数都是合数。
11行:这里开始了一个 for 循环,循环的范围是从5到int(num**0.5)+1
,步长为6。这个循环的设计是高效的,因为它只检查了可能是素数的一部分数字。所有大于3的素数都可以表示为6k±1的形式,其中k是自然数,因为所有形如6k的数都可以被2和3整除,所以不可能是素数。
12-13行:在循环内部,检查num
是否能被i
或i+2
整除。如果能,那么num
不是素数,返回 False。
15行:如果循环结束都没有找到能整除num
的数,那么num
是素数,返回 True。
总体来说,这段代码是高效的,因为它避免了不必要的检查,并且利用了素数的性质来减少计算量。这种方法的效率很高,尤其是对于较大的数。代码的逻辑清晰,注释也很好地解释了每一步的目的。这是一个很好的素数判定函数的实现。
对2.4节代码的解析
1-4行:首先检查输入的数值是否超过函数的处理范围(10^6 - 1)。如果是,则打印一条消息并退出函数,返回 None。这里使用了一个格式化字符串来打印居中的消息,并且使用了脱字符号~
来填充空白。
6行:如果输入的数值小于2,直接返回 False,因为2是最小的素数。
8行:对于2到4之间的数,直接返回 True,因为它们都是素数。
10行:如果num
是2或3的倍数,则返回 False,因为合数肯定能被2或3整除。
12行:定义了一个包含小于1000的所有素数的元组myprimes
,这些素数都是大于5的。之所以只需要这些素数,是因为前面的代码已经排除了2和3的倍数。
13行:通过iter
函数将myprimes
转换为一个迭代器。这样做是为了在接下来的循环中逐个使用这些素数。
15-17行:使用一个 for 循环遍历myprimes
中的素数。循环中有一个判断,一旦当前素数的平方大于num
,就结束循环。这是因为如果一个数不是素数,那么它必定有一个因子是小于或等于它的平方根的。
18行:在循环中,如果num
能够被当前素数整除,那么num
不是素数,函数返回 False。
20行:如果循环结束都没有找到能整除num
的素数,那么num
是素数,函数返回 True。
整体来看,这个函数通过排除法来确定一个数是否为素数。它首先排除那些明显不是素数的数(小于2的数和2或3的倍数),然后通过只检查小于1000的素数来减少计算量。这种方法的效率相对较高,尤其是对于较小的数。然而,对于非常大的数,这种方法可能不是最优的,因为它需要预先定义一个相对较大的素数列表。
3、结语
代码没有“最好”只有“更好”,根据实际需求选择适宜的算法和相应的“代码表现形式”,才是“代码编撰”最正确的打开方式。
4、我关于“素数”的学习笔记
- 5个写自定义函数小练习
地址:https://blog.csdn.net/m0_57158496/article/details/134321362
浏览阅读:508
点赞:2 收藏:2 评论:2
(本篇笔记于2023-11-10 00:37:19首次发布,最后修改于2023-11-10 22:48:13)
- 幸运素数(找出给定区间的所有幸运素数)
地址:https://blog.csdn.net/m0_57158496/article/details/134346918
浏览阅读:341
点赞:1 收藏:2
(本篇笔记于2023-11-11 12:59:47首次发布,最后修改于2023-11-11 22:30:33)
- 素数查找(def自定义函数练习)
地址:https://blog.csdn.net/m0_57158496/article/details/118497087
浏览阅读:332
回页目录
5、完整源码(Python)
(源码较长,点此跳过源码)
#!/sur/bin/nve python # coding: utf-8 from time import timedef isPrime(num: int) -> bool:if num > 10**6-1:input(f"\n{' 本函数仅限于查找10^6以内的素数 ':~^28}")return # 退出代码执行返回命令行if num < 2:return False # 剔除2以下的数if 1 < num < 4:return Trueif num%2 == 0 or num%3 == 0:return Falsemyprimes = (5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997) # 1000以内大于5的素数,由于前面已剔除2、3的倍数,就不再试除2、3。本列表仅限于查找100w以内的素数myprimes = iter(myprimes)for i in myprimes:if i*i > num:break if num%i == 0:return Falsereturn True#isPrime(1000_000+1) # 调试报错提示def is_prime(num: int) -> bool:if num < 2:return Falseif num < 4:return Trueif num % 2 == 0 or num % 3 == 0:return False# 使用 for 循环代替 while 循环for i in range(5, int(num**0.5) + 1, 6):if num % i == 0 or num % (i + 2) == 0:return Falsereturn Truedef isPrime4(num: int) -> bool:''' 素数判定 '''if num < 2:return False # 小于2的都不是素数if num == 2 or num == 3:return True # 2和3都是素数elif num%2 == 0 or num%3 == 0:return False # 剔除2、3的倍数for i in range(5, int(num**0.5)+1, 6): # 只检查6k±1的自然数if num%i == 0 or num%(i+2) == 0: return False # 大于5的素数都满足6k±1的形式,6k形式的数一定是合数return True # 经过前面的排查,就只剩素数了#n = 100 n: int = 1000_000 start = time() #primes = [i for i in range(n) if is_prime(i)] primes = [i for i in range(n) if isPrime(i)]if (k := len(primes))<= 100:print(f"\n{primes}")print(f"\n找到{n}以内的素数有{k}个\n(用时{time()-start:.4f}秒)")
回页首
上一篇: CSDN上的代码块放置(三种方式实现,CSDN文章中代码文本的标准放置,方便阅读者copy,让代码更易于传播)
下一篇:
我的HOT博:
本次共计收集 311 篇博文笔记信息,总阅读量43.82w。数据于2024年03月22日 00:50:22完成采集,用时6分2.71秒。阅读量不小于6.00k的有 7 7 7篇。
-
001
标题:让QQ群昵称色变的神奇代码
(浏览阅读 5.9w )
地址:https://blog.csdn.net/m0_57158496/article/details/122566500
点赞:25 收藏:86 评论:17
摘要:让QQ昵称色变的神奇代码。
首发:2022-01-18 19:15:08
最后编辑:2022-01-20 07:56:47 -
002
标题:Python列表(list)反序(降序)的7种实现方式
(浏览阅读 1.1w )
地址:https://blog.csdn.net/m0_57158496/article/details/128271700
点赞:8 收藏:35 评论:8
摘要:Python列表(list)反序(降序)的实现方式:原址反序,list.reverse()、list.sort();遍历,全数组遍历、1/2数组遍历;新生成列表,resersed()、sorted()、负步长切片[::-1]。
首发:2022-12-11 23:54:15
最后编辑:2023-03-20 18:13:55 -
003
标题:pandas 数据类型之 DataFrame
(浏览阅读 9.7k )
地址:https://blog.csdn.net/m0_57158496/article/details/124525814
点赞:7 收藏:36
摘要:pandas 数据类型之 DataFrame_panda dataframe。
首发:2022-05-01 13:20:17
最后编辑:2022-05-08 08:46:13 -
004
标题:个人信息提取(字符串)
(浏览阅读 8.2k )
地址:https://blog.csdn.net/m0_57158496/article/details/124244618
点赞:2 收藏:15
摘要:个人信息提取(字符串)_个人信息提取python。
首发:2022-04-18 11:07:12
最后编辑:2022-04-20 13:17:54 -
005
标题:Python字符串居中显示
(浏览阅读 7.6k )
地址:https://blog.csdn.net/m0_57158496/article/details/122163023
评论:1 -
006
标题:罗马数字转换器|罗马数字生成器
(浏览阅读 7.5k )
地址:https://blog.csdn.net/m0_57158496/article/details/122592047
摘要:罗马数字转换器|生成器。
首发:2022-01-19 23:26:42
最后编辑:2022-01-21 18:37:46 -
007
标题:回车符、换行符和回车换行符
(浏览阅读 6.0k )
地址:https://blog.csdn.net/m0_57158496/article/details/123109488
点赞:2 收藏:3
摘要:回车符、换行符和回车换行符_命令行回车符。
首发:2022-02-24 13:10:02
最后编辑:2022-02-25 20:07:40
推荐条件 阅读量突破6.00k (更多热博,请点击蓝色文字跳转翻阅)
截屏图片
(此文涉及ChatPT,曾被csdn多次下架,前几日又因新发笔记被误杀而落马。躺“未过审”还不如回收站,回收站还不如永久不见。😪值此年底清扫,果断移除。留此截图,以识“曾经”。2023-12-31)
回页首
精品文章:
- 好文力荐:齐伟书稿 《python 完全自学教程》 Free连载(已完稿并集结成书,还有PDF版本百度网盘永久分享,点击跳转免费🆓下载。)
- OPP三大特性:封装中的property
- 通过内置对象理解python'
- 正则表达式
- python中“*”的作用
- Python 完全自学手册
- 海象运算符
- Python中的 `!=`与`is not`不同
- 学习编程的正确方法
来源:老齐教室
◆ Python 入门指南【Python 3.6.3】
好文力荐:
- 全栈领域优质创作者——[寒佬](还是国内某高校学生)博文“非技术文—关于英语和如何正确的提问”,“英语”和“会提问”是编程学习的两大利器。
- 【8大编程语言的适用领域】先别着急选语言学编程,先看它们能干嘛
- 靠谱程序员的好习惯
- 大佬帅地的优质好文“函数功能、结束条件、函数等价式”三大要素让您认清递归
CSDN实用技巧博文:
- 8个好用到爆的Python实用技巧
- python忽略警告
- Python代码编写规范
- Python的docstring规范(说明文档的规范写法)
-