质数又称素数。指整数在一个大于1的天然数中,除了1和此整数自身外,无法被其余天然数整除的数。换句话说,只有两个正因数(1和本身)的天然数即为素数。比1大但不是素数的数称为合数。1和0既非素数也非合数。素数在数论中有着很重要的做用。
质数的分布规律是以36N(N+1)为单位,随着N的增大,素数的个数以波浪形式渐渐增多。
孪生质数也有相同的分布规律。 python
素数,广泛认为的分布规律是没有规律。时而连续出现,时而又相隔很远很远。有远亲、有近邻,地球对面也还有几个好朋友。
素数,真的就没有规律吗?
合数能够用公式来表示,而素数且不能用公式来表示。这就是素数。
不过这里其实就蕴含着秘密。
既然合数能用公式表示,间接的也就说明了,素数必须服从这些公式的限制。而研究合数,其实也是研究素数。
有2个根深蒂固的观念:
一、素数的个数老是按照天然数增长10倍来统计展示的。由于这里一直沿用π(x)与x/lnx的统计方法。
二、100之内有25个素数,1000之内有168个素数。就产生了一种根深蒂固的观念:素数愈来愈稀疏。
固然这些都没有错误,不然也不会一直陪伴着素数研究到如今,但它禁锢了人们的思想。有一些数据彷佛与之相悖。
列举一些四胞胎素数的例子,
四胞胎素数是不多的,在天然数1000亿之内仅仅有1209317组。平均间距为82691。两组之间相距是很远的。但总有一些间距仅仅为30的两对四胞胎素数稀稀拉拉的出现。在1000亿之内共有这样四胞胎素数267对,他们是如何分布的呢?
200亿之内有90个;200-400亿之间有55个;
剩下的如何分布的呢,你不会相信的:
400-600亿之间有41个;
600-800亿之间有41个;
800-1000亿之间有40个;
这样的分布说明了什么?均匀分布?你们确定不会相信的,我也不信,那彷佛就只能是巧合了。你们必定也会认为是这纯属巧合。素数嘛,飘忽不定,怎么分布都有可能,但就是没有规律。至少你们尚未发现其分布规律。算法
count = 0 for i in range(2,101): for x in range(2,i): if i%x == 0: break else: print(i) count += 1 print("\n","Total: ",count,"number") ---- 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 Total: 25 number
这种方法的思路,时间复杂度是O(n²),2层循环,虽然会break,但效率仍是很低的app
其实咱们发现咱们求解质数的时候,根本不须要从2除到N-1,当除数大于商的时候咱们就不用计算了。
用数学的话来讲咱们只需除到平方根就行了ide
count = 0 for i in range(2,100000): for x in range(2,int(i**0.5)+1): if i%x == 0: break else: print(i) count += 1 print("\n","Total: ",count,"number") ---- 2 3 5 7 11 13 ······· 99907 99923 99929 99961 99971 99989 99991 Total: 9592 number
因此对于偶数都不用判断是否是素数,修改步长区块链
count = 1 print(2) for i in range(3,100000,2): for x in range(2,int(i**0.5)+1): if i%x == 0: break else: print(i) count += 1 print("\n","Total: ",count,"number") ---- 2 3 5 7 11 13 ······· 99907 99923 99929 99961 99971 99989 99991 Total: 9592 number
第二层for循环判断的是奇数/range(2,奇数的开方)
可是2,4,6,8···
这种数确定不能被奇数整除,不用考虑,能够不加判断测试
count = 1 print(2) for i in range(3,100000,2): for x in range(3,int(i**0.5)+1,2): if i%x == 0: break else: print(i) count += 1 print("\n","Total: ",count,"number") ---- 2 3 5 7 11 13 ······· 99907 99923 99929 99961 99971 99989 99991 Total: 9592 number
计算以上的程序运行时间,取1000000之内的质数优化
from datetime import datetime t1 = datetime.now() count = 0 for i in range(2,1000000): for x in range(2,i): if i%x == 0: break else: #print(i) count += 1 print("\n","Total: ",count,"number") t2 = datetime.now() print("Total_Cost:",(t2-t1).total_seconds(),"s")
我喝了一杯咖啡,还没计算完...已经超过五分钟了,不等了
而后减小10倍,测试100000之内的数据...用了40s
code
from datetime import datetime t1 = datetime.now() count = 0 for i in range(2,1000000): for x in range(2,int(i**0.5)+1): if i%x == 0: break else: #print(i) count += 1 print("\n","Total: ",count,"number") t2 = datetime.now() print("Total_Cost:",(t2-t1).total_seconds(),"s") ---- Total: 78498 number Total_Cost: 6.26467 s
用了6.26467s
,效率大大提高内存
from datetime import datetime t1 = datetime.now() count = 1 #print(2) for i in range(3,1000000,2): for x in range(2,int(i**0.5)+1): if i%x == 0: break else: # print(i) count += 1 print("\n","Total: ",count,"number") t2 = datetime.now() print("Total_Cost:",(t2-t1).total_seconds(),"s") ---- Total: 78498 number Total_Cost: 5.80345 s
用了5.80345s
,效率稍微进步数学
from datetime import datetime t1 = datetime.now() count = 1 #print(2) for i in range(3,1000000,2): for x in range(3,int(i**0.5)+1,2): if i%x == 0: break else: #print(i) count += 1 print("\n","Total: ",count,"number") t2 = datetime.now() print("Total_Cost:",(t2-t1).total_seconds(),"s") ---- Total: 78498 number Total_Cost: 3.375002 s
用了3.375002s
,效率约提升50%
from datetime import datetime t1 = datetime.now() count = 1 lst = [2] for i in range(3,1000000,2): #for x in range(3,int(i**0.5)+1,2): for x in lst: if i%x == 0 and x <= i**0.5: break else: lst.append(i) count += 1 t2 = datetime.now() print("Total Number:", count, "Total_Cost:", (t2-t1).total_seconds(),"s") ---- Total Number: 78498 Total_Cost: 234.643142 s
由于每次都要if判断两次结构(a and b),效率会低,修改下方案
from datetime import datetime t1 = datetime.now() count = 1 lst = [2] for i in range(3,1000000,2): flag = False middle = int(i**0.5) for x in lst: if i%x == 0: break if x > middle: flag = True break if flag: lst.append(i) count += 1 t2 = datetime.now() print("Total Number:", count, "Total_Cost:", (t2-t1).total_seconds(),"s") ---- Total Number: 78498 Total_Cost: 1.560107 s
能够能够,上面的方法四计算1000000内素数用时是3.37s,而如今,只须要1.56s,效率又提升50%以上
有一个数在作无用功,它就是2,任何素数都不能整除2
from datetime import datetime t1 = datetime.now() count = 2 #[2] lst = [3] for i in range(5,1000000,2): flag = False middle = int(i**0.5) for x in lst: if i%x == 0: break if x > middle: flag = True break if flag: lst.append(i) count += 1 t2 = datetime.now() print("Total Number:", count, "Total_Cost:", (t2-t1).total_seconds(),"s") ---- Total Number: 78498 Total_Cost: 1.513069 s
略微提高,也有效果
还有吗?
在求无限质数的时候,咱们不能预测有多少结果
可是对于求1000000内质数,咱们如今知道了有多少结果
这样就能够提早开辟内存空间,替代append()
还有别的方法吗?固然有!孪生素数了解下
孪生素数就是指相差2的素数对,例如3和5,5和7,11和13…。孪生素数猜测正式由希尔伯特在1900年国际数学家大会的报告上第8个问题中提出,能够这样描述:存在无穷多个素数p,使得p + 2是素数。素数对(p, p + 2)称为孪生素数。
总结下来就是一句话:当素数大于3时,素数都在 6N-1 和 6N+1 左右分布
素数 | 2 | 3 | 5 | 7 | 11 | 13 | 17 | 19 | 23 | 25 |
---|---|---|---|---|---|---|---|---|---|---|
步长 | 2 | 4 | 2 | 4 | 2 | 4 | 2 | 4 |
由此,在循环中用一个可变步长就能够,C语言有可变步长;
然而Python没有可变步长这一说- -
下面上代码实现
from datetime import datetime t1 = datetime.now() count = 3 #2,3,5 lst = [3,5] step = 4 i = 7 while i < 1000000: if i%5 != 0: middle = int(i**0.5) flag = False for x in lst: if i%x == 0: break if x > middle: flag = True break if flag: lst.append(i) count += 1 i += step step = 4 if step == 2 else 2 t2 = datetime.now() print("Total Number:", count, "Total_Cost:", (t2-t1).total_seconds(),"s") ---- Total Number: 78498 Total_Cost: 1.35155 s
1.513069s
—> 1.35155s
还能够哈哈
量子计算机,了解一下......密码学、区块链都将被从新定义~