前几天,有个非计算机专业的同学问我,如何快速找出1亿之内的孪生素数——所谓孪生素数,就是差值为2的两个素数。原本以为这是一个很简单的问题,随便用python写了一个方法,没想到却要跑17分钟左右。改用C++试试,受限于我对C/C++的理解程度,仍然慢得无法承受(此处绝无小视C++之意)。这个问题激起了我的兴趣。于是乎,我花了半天时间,尝试了几种方式,最终又对代码做了优化,终于在3秒钟内找出了小于1亿的素数表。

略微得意了3秒钟,突然想到,Python 这个速度究竟是什么水平呢?用 C/C++/Java/Go/Rust 等语言实现起来会不会更快呢?如果大家一起来个擂台赛,会不会很热闹?各位 C/C++/Java/Go/Rust 的高手们,有兴趣一起搞个擂台赛吗?没准儿,CSDN会为这个活动设置奖项呢(哈哈哈。。。)

11月6日追记:今天,有几位朋友在评论区留言,冷嘲热讽,不太友好。一开始我还逐一认真回复,后来想,算了,统一在这里说一下吧:1. 作为从业二十余年的老程序员,从事科学计算多年,深知C/C++语言的效率,也了解目前数学运算的速度,如各位担心我忘记了,请尽量心平气和地提醒我;2. 本文写作的目的,仅仅是出于探讨如何提高python计算速度的目的,并没有轻视某种语言,且在开篇已经声明;3. 所有人都知道速度是python的短板,之所以取这样的名字,不否认有博眼球的用意,但也是想给CSDN提个建议,搞一些跨界活动,给大家弄点纪念品;4. 作为脚本语言python能跑出2.4秒的成绩,你用C++也是2点几秒,即使更快,似乎也没有蔑视嘲讽他人的资格;5. 我已过知天命之年,再激烈的言辞也可以接受,不会删除评论,最大限度尊重言论自由,也请评论者尽量保持平和的心态。

1. 找出1百万以内的质数,大约3秒钟

咸盐稍许,先给出我的最原始的算法。运行 prime_1.py,找出100万以内的质数,大约3秒钟。不要试图尝试更大范围的寻找,那会花更长的时间,长到你无法忍受。

prime_1.py

# -*- coding: utf-8 -*-

import sys, time

from math import sqrt

def find_prime(upper):

"""找出小于upper的所有质数"""

prime_list = list() # 存放找到的质数

for i in range(2, upper): # 从2开始,逐一甄别是否是质数

is_prime = True # 假设当前数值i是质数

for p in prime_list: # 遍历当前已经找到的质数列表

if i%p == 0:

is_prime = False

break

elif p > sqrt(i):

break

if is_prime:

prime_list.append(i)

return prime_list

upper = 1000000

t0 = time.time()

prime_list = find_prime(upper)

t1 = time.time()

print('查找%d以内的质数耗时%0.3f秒,共找到%d个质数'%(upper, t1-t0, len(prime_list)))1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

2. 找出1千万以内的质数,大约12秒钟

3秒钟找出100万以内的质数,这个效率,显然无法用于查找1亿以内的素数。下面的代码,我使用了numpy这个科学计算库,速度提升明显。运行 prime_2.py,找出1千万以内的质数,大约12秒钟。不过要是用它来查找1亿以内的质数,至少需要15分钟。

prime_2.py

# -*- coding: utf-8 -*-

import sys, time

import numpy as np

"""

网上有文章说,python最强找质数程序,寻找10万以内质数只要30秒哦!

运行一下我们这个脚本,找出1千万内的质数,大约11秒

不要尝试找出1亿内的质数,你等不到结果。别说我没告诉你!!!

"""

def find_prime(upper):

"""找出小于upper的所有质数"""

prime_list = list() # 空数组,用于存放找到的质素

mid = int(np.sqrt(upper)) # 判断100是否是质数,只需要分别用2,3...等质素去除100,看能否被整除,最多做到100的平方福根就够了

nums = np.arange(upper) # 生成0到上限的数组,数组元素的值等于其索引号,相对于python的[0,1,2,3,...]

nums[1] = 0 # 数组第1和元素置0,从2开始,都是非0的

while True: # 循环

primes = nums[nums>0] # 找出所有非0的元素

if primes.any(): # 如果能找到

p = primes[0] # 则第一个元素为质数

prime_list.append(p) # 保存第一个元素到返回的数组

nums[p::p] = 0 # 这个质数的所有倍数,都置为0(表示非质素)

if p > mid: # 如果找到的质数大于上限的平方根

break # 则退出循环

else:

break # 全部0,也退出循环

prime_list.extend(nums[nums>0].tolist()) # nums里面剩余的非0元素,都是质数,合并到返回的数组中

return prime_list # 返回结果

upper = 10000000

t0 = time.time()

prime_list = find_prime(upper)

t1 = time.time()

print('查找%d以内的质数耗时%0.3f秒,共找到%d个质数'%(upper, t1-t0, len(prime_list)))1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

3. 找出1亿以内的质数,耗时不到3秒钟!

上面的代码还有优化的空间吗?经过分析发现,numpy 的 ndarray 对象,其元素数量超过一定范围后,效率明显变慢。针对这一点,我做了分块优化。运行 prime_3.py,找出1亿以内的质数,耗时不到3秒钟!

prime_3.py

# -*- coding: utf-8 -*-

import sys, time

import numpy as np

"""

网上有文章说,python最强找质数程序,寻找10万以内质数只要30秒哦!

运行一下我们这个脚本,找出1亿以内的质数,耗时不到3秒,比上面快了大约1万倍

还可以尝试更大的范围,但步子不要太大!!!

"""

def find_prime(upper):

"""找出小于upper的所有质数"""

prime_list = list()

mid = int(np.sqrt(upper))

nums = np.arange(upper)

nums[1] = 0

while True:

primes = nums[nums>0]

if primes.any():

p = primes[0]

prime_list.append(p)

nums[p::p] = 0

if p > mid:

break

else:

break

prime_list.extend(nums[nums>0].tolist())

return prime_list

def fast_find_prime(upper, base=100000, block=20000000):

"""快速找出小于upper的所有质数"""

if upper <= base:

return find_prime(upper)

mid = int(np.sqrt(upper))

prime_list = find_prime(base)

prime_array = np.array(prime_list)

prime_array = prime_array[prime_array<=mid]

start = base

while start < upper:

end = start + block

if end > upper:

end = upper

print((start, end))

prime_list.extend(process_func(start, np.copy(prime_array), (start, end)))

start += block

return prime_list

def process_func(id, primes, task_range):

"""执行分块任务的函数

primes - 用以剔除非质数的质数表

task_range - 分块任务的数值范围

"""

nums = np.arange(task_range[0], task_range[1])

for p in primes:

k = (p-task_range[0]%p)%p

nums[k::p] = 0

return nums[nums>0].tolist()

upper = 100000000

t0 = time.time()

prime_list = fast_find_prime(upper)

t1 = time.time()

print('查找%d以内的质数耗时%0.3f秒,共找到%d个质数'%(upper, t1-t0, len(prime_list)))1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

后记

近期有很多朋友通过私信咨询有关python学习问题。为便于交流,我创建了一个名为“python程序员进阶之路”的微信群,还在CSDN的app创建了一个小组,名为“python作业辅导小组”,面向python初学者,为大家提供咨询服务、辅导python作业。欢迎有兴趣的同学扫码加入。

java四个数打擂,荐 C/C++/Java/Go/Rust,Python喊你来打擂:3秒钟内统计出小于1亿的素数个数...相关推荐

  1. C/C++/Java/Go/Rust,Python喊你来打擂:3秒钟内统计出小于1亿的素数个数

    前几天,有个非计算机专业的同学问我,如何快速找出1亿之内的孪生素数--所谓孪生素数,就是差值为2的两个素数.原本以为这是一个很简单的问题,随便用python写了一个方法,没想到却要跑17分钟左右.改用 ...

  2. JAVA 四种引用类型和垃圾回收器

    JAVA 四种引用类型 强引用 在 Java 中最常见的就是强引用,把一个对象赋给一个引用变量,这个引用变量就是一个强引用.当一个对象被强引用变量引用时,它处于可达状态,它是不可能被垃圾回收机制回收的 ...

  3. Java求n以内素数_求0到n之间素数个数的序列(Java)

    要求: (1) 找出0-1000之间素数 (2) 设f(n)表示0-n之间的素数个数,计算出当n=0,1,2,3,.....,997时f(n)的值,并写入文件 分析: 首先找素数使用一个效率较高的方法 ...

  4. Bailian3177 判决素数个数【入门】(POJ NOI0113-10)

    问题链接:POJ NOI0113-10 判决素数个数. 判决素数个数 总时间限制: 1000ms 内存限制: 65536kB 描述 输入两个整数X和Y,输出两者之间的素数个数(包括X和Y). 输入 两 ...

  5. [转]new Thread的弊端及Java四种线程池的使用

    介绍new Thread的弊端及Java四种线程池的使用,对Android同样适用.本文是基础篇,后面会分享下线程池一些高级功能. 1.new Thread的弊端 执行一个异步任务你还只是如下new ...

  6. java四类八种基本数据类型

    java基本数据类型就8种,除了这些都是引用型的了.  一.java四类八种基本数据类型 第一类:整型 byte short int long 第二类:浮点型 float double 第三类:逻辑型 ...

  7. java四类八种_java四类八种基本数据类型

    Java基本数据类型就8种,记住就好了.除了这些都是引用型的了. java四类八种基本数据类型 第一类:整型 byte short int long 第二类:浮点型 float double 第三类: ...

  8. 闲聊蓝桥杯JAVA - 四平方和

    闲聊蓝桥杯JAVA - 四平方和 D:这道题有一点复杂,看了 四平方和四平方和定理,又称为拉格朗日定理: 每个正整数都可以表示为至多4个正整数的平方和. 如果把0包括进去,就正好可以表示为4个数的平方 ...

  9. java(四)【常用API,自定义泛型、collection接口】

    day04[常用API.正则表达式,泛型.Collection集合API] 主要内容 Date类 Java是面向对象的思想,会用一个类来代表一个事物. Date代表了系统当前此刻日期对象!年月日时分秒 ...

最新文章

  1. nodejs php web,nodejs实现的简单web服务器功能示例
  2. antd option宽度自适应_Web移动端实现自适应缩放界面的方法汇总
  3. 如何处理网络丢包故障?—Vecloud微云
  4. SpringBoot的构造方法中使用@AutoWird注入的类会报错null
  5. Silverlight通过Wcf Data Service访问数据库之ADO.NET Entity Framework篇
  6. Java使用lambda进行分页,SpringBoot(八):整合mybatis,通用mapper,分页插件,lambda,Logger,junit用法...
  7. Intellij IDEA 配置 Code Style
  8. 阿言学习之Hadoop fs常用命令
  9. Servlet+jsp入门教程
  10. python sorted方法
  11. linux格式化后恢复 vmdk恢复,根据flat.vmdk文件恢复磁盘(完善版)
  12. 计算机右键菜单太多,鼠标右键菜单选项太多:清理多余菜单选项的方法
  13. 解决kettle部署在linux中界面变成英文的问题
  14. 使用xshell登陆腾讯云主机
  15. CB Insights:全面拆解谷歌AI战略布局
  16. 在虚拟机关机时,提示Ubuntu-Unattended upgrade in progress during shutdown, please don‘t turn off
  17. 计算机页面排版的笔记,推荐6种简单实用的手绘笔记排版
  18. mysql 查看slow query_MySQL慢查询日志(slow log)
  19. linux docker升级,Docker 升级到最新版本
  20. 谈谈找工作过程中的那些环节、注意点和经验

热门文章

  1. HTTP协议与网络编程(二)HTTP消息
  2. Linux串口调试助手
  3. MPEG音频编码实验
  4. ubuntu系统输入法切换_Ubuntu 安装中文输入法 小白版
  5. USACO COWXOR
  6. 又一个加密PHP脚本的解码方法
  7. 联想MIIX520笔记本电脑屏幕亮度无法调节问题
  8. make menuconfig学习
  9. 游戏汉化教程1-汉化流程
  10. 德州扑克多个玩家对局时赢牌牌型概率分布表、各种牌型的出现概率