600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > python判断孪生质数对(素数对)并计算个数。

python判断孪生质数对(素数对)并计算个数。

时间:2018-11-10 11:47:03

相关推荐

python判断孪生质数对(素数对)并计算个数。

很久前在知乎写的一个答案,今天把坑填了,顺便搬过来。

让我们定义dn为:dn=pn+1−pn,其中pi是第i个素数。显然有d1=1,且对于n>1有dn是偶数。

“素数对猜想”认为“存在无穷多对相邻且差为2的素数”。 现给定任意正整数N(<10^5), 请计算不超过N的满足猜想的素数对的个数。

而且题目还限制了400ms时间(有没有搞错(╯‵□′)╯︵┻━┻)

写出的第一个程序在最大值情况下运行时间超过10秒 (;′⌒`)

后来在网上看到了一个人的回答,使用到了初中时学到的数学知识:

假如一个数N是合数,它有一个约数a,那么有a×b=N

则a、b两个数中必有一个大于或等于根号N,一个小于或等于根号N。

因此,只要小于或等于根号N的数(1除外)不能整除N,则N一定是素数。

原谅我数学没学好,依照这个思路 我写了下面这个程序:

import math #使用 math 模块来开平方import time #计算程序运行时间num = int(input()) #输入一个整数s = 0 #计算质数对的个数start = time.time() #计算开始时间def f1(n):if n <= 1:return Falseelse:for i in range(2, int(math.sqrt(n)) + 1): #这里 +1是将开方后的结果包含在内if n % i == 0:return False return True for i in range(1, num+1):if f1(i) is True and f1(i + 2) is True and (i + 2) <= num: #最后的条件是限制素数对超过Ns += 1end = time.time() #结束时间print(s)#打印素数对个数print(end - start)#输出运行时间

嗯 这就是大概的逻辑,最后时间大大缩短,用100000来实验,时间是0.4561。略微超过了400ms。

怎么办…… 于是继续找,总有人跟我遇到一样的问题嘛?

最后还真找到了!

要想继续优化缩短运行时间,就是按照上面的思路来排除多余的工作量。既然我们已经排除了一半,那是不是还能排除跟多呢?

废话!当然可以啦~(不然也不会写到这里)

首先想到的就是偶数! 除了2以外,显然偶数不是素数。好的,又排除了一半。

顺着思路,那么奇数里面能被3,被5整除的也要排除。

顺着这个思路 我们得到这个代码:

import math# 使用 math 模块来开平方import time# 计算程序运行时间num = int(input()) # 输入一个整数s = 0 # 计算质数对的个数start = time.time() # 计算开始时间def f1(n):if n <= 1:return Falseelif n % 2 == 0 and n != 2:# 去除能被2整除的 不包括2(其实也可以包括2,以为2没有素数对)return Falseelif n % 3 == 0 and n != 3:# 去除能被3整除的 不包括3return Falseelif n % 5 == 0 and n != 5:# 去除能被5整除的 不包括5return Falseelif n % 7 == 0 and n != 7:# 去除能被7整除的 不包括7return Falseelse:for i in range(3, int(math.sqrt(n)) + 1, 2): # 这里 +1是将开方后的结果包含在内if n % i == 0:return Falsereturn Truefor i in range(1, num+1):if f1(i) is True and f1(i + 2) is True and (i + 2) <= num: # 最后的条件是限制素数对超过Ns += 1end = time.time()print(s)print(end - start)

用 100000 来实验,得到的时间是207ms!!! 合格啦!!! 少了一半多! 但是能不能更少呢?

还真能!

要想再简化,就不得不了解孪生质数的性质和分布规律。

一. 当n≥5时,如果一个n-1,n+1互为孪生质数,则n必定是6的倍数

简要证明:因为:n - 1,n + 1是质数 故 :n - 1 ,n + 1是奇数可知:n 是 偶数,n 是 2 的倍数。假设:n 不是 3 的倍数,即 n = 3k + 1 或 n = 3k + 2。 (a) 当 n = 3k + 1 时,那么 n - 1 = 3k,已经与 n - 1 是质数矛盾。(b) 当 n = 3k + 2 时, 那么 n +1=3(k + 1),已经与 n + 1是质数矛盾。故:n 是 3 的倍数。因为:n既是2的倍数,又是3的倍数故:n 是6的倍数。

得出:

推论一:当 x >= 1, (6x - 1)或 (6x + 1)不是质数时,即

2(3x) - 1, 3(2x) - 1,

2(3x) + 1, 3(2x) + 1,为合数时,

它们的质因子不包括2和3的倍数。(合数为可分解为多个质数的乘积)

二. 对于大于3的质数,只分布在6x-1和6x+1两数列中(x为非0自然数)。即都在6的倍数的两侧。

也就是说,大于5的质数一定在6x两侧,但是6x的两侧不一定是质数。

6x-1数列中的素数为阴性素数,合数为阴性合数

6x+1数列中的素数为阳性素数,合数为阳性合数

好了,依照之前的和以上两个性质的思路。

可知,对于大于3的孪生质数

5+6n数列中,素数必定为阴性素数,且合数也不能被2,3整除,所以是否能被2,3整除不用判断只需满足5+6n和7+6n同时为素数,即都不能被5或7 整除即可。

代码如下:

import math# 使用 math 模块来开平方num = 100000s = 1 # 默认考虑(3,5)def f1(n):if n == 5 or n == 7:return Trueelif n % 5 == 0 and n % 7 == 0:return Falseelse:for i in range(3, int(math.sqrt(n)) + 1, 1): # 这里 +1是将开方后的结果包含在内。if n % i == 0:return Falsereturn Truefor i in range(5, num+1, 6):if f1(i) and f1(i+2) and (i+2)<=num: # 最后的条件是限制素数对超过Ns += 1# print((i,i+2),s)print(s)

最终用时为85ms!!!,又少了一半多!!!

这个是从判断是否为孪生素数对的角度来寻找思路,对于是否为素数,我想也没必要赘述了。按照以上思路写就可以了。

其实从这个小练手让我学到了一件事,在做一些事情之前,不要一开始就闷着头干,先思考,分析,才能真正抓住事情的本质,得出更满意的结果。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。