埃拉托色尼素数筛选法的证明及原理
一、什么是素數(shù)?
素數(shù)又稱為質(zhì)數(shù)。素數(shù)定義為在大于1的自然數(shù)中,除了1和它本身以外不再有其他因數(shù)。素數(shù)在日常中最多的應(yīng)用就是加密算法,例如RSA加密算法就是基于來實(shí)現(xiàn)的。RSA算法會隨機(jī)生成兩個1024位的質(zhì)數(shù)相乘,要破解密碼必須對乘積做質(zhì)因數(shù)分解,而1024位的質(zhì)因數(shù)分解是非常困難的。
二、如何快速的算出小于某個數(shù)的所有素數(shù)?
從素數(shù)的概念上似乎可以很快得出一個算素數(shù)的公式,即將一個數(shù)循環(huán)做除法,從1一直除到它本身,如果中途只有被1和自己整除了這個數(shù)便是素數(shù)了,這樣的計(jì)算效率是非常差的,因?yàn)樗麜煌5谋闅v整個數(shù)據(jù)范圍。我們來試著跑一下它的效率:
#求10萬以內(nèi)的素數(shù)
import datetime
start = datetime.datetime.now()
for i in range(2,100000):
for j in range(2,i):
if i%j == 0:
break
#else:
#print(i)
stop = datetime.datetime.now()
print(stop-start)
運(yùn)行結(jié)果:0:01:04.326679,在沒有print的情況下竟然用了1分多鐘,并且數(shù)字越大計(jì)算越慢。這樣的效率肯定是不被允許的。下面介紹一種最常見的質(zhì)數(shù)算法的原理:
三、埃拉托色尼素數(shù)篩選法
埃拉托色尼是一名古希臘的地理學(xué)家,他是世界上第一個計(jì)算出地球周長的人。埃拉托色尼素數(shù)篩選法可以很快速的計(jì)算出1到N之間的所有素數(shù)。將n開根號,即N^0.5,去掉2到N^0.5中所有素數(shù)的倍數(shù),剩下的數(shù)便都是素數(shù)了。例如求1到25中的素數(shù)有哪些,第一步是將25開根號,得到5;第二步將2到5的素數(shù)取出來,分別是2、3、5;再將2到25中且是2、3、5的倍數(shù)的數(shù)去掉,即去掉4、6、8、9、10、12、14、15、16、18、20、21、22、24、25,剩下2、3、5、7、11、13、17、19便是1到25中的所有素數(shù)了。
這里還用到了一個數(shù)學(xué)知識,即只要小于或等于根號N的數(shù)(1除外)不能整除N,則N一定是素數(shù);反過來說就是只要小于或等于根號N的數(shù)(1除外)能整除N,則N一定是合數(shù)。下面給出證明過程:
假設(shè)一個數(shù)N是合適,那一定存在一個因數(shù)b和一個非1且非自身的因數(shù)a,即a*b=N
等式兩邊同時開根號得出:(a*b)^0.5=a^0.5*b^0.5=N^0.5
可以推出:若N為合數(shù),則a和b中一定有一個大于或等于N^0.5,另一個小于或等于N^0.5
按照這個結(jié)論,就只需計(jì)算小于等于N^0.5的數(shù)了,這樣就大大提高了效率(要注意等于N^0.5的這個邊界):
#求10萬以內(nèi)的素數(shù)
import datetime
start = datetime.datetime.now()
for i in range(2,100000):
for j in range(2,int(i**0.5+1)): #邊界需要加1
if i%j == 0:
break
#else:
#print(i)
stop = datetime.datetime.now()
print(stop-start)
運(yùn)行結(jié)果:0:00:00.428024。可以說是質(zhì)的飛躍。
再優(yōu)化
我們也可以將偶數(shù)事先就排除在外,然后在進(jìn)行素數(shù)篩選:
#求10萬以內(nèi)的素數(shù)
import datetime
start = datetime.datetime.now()
print(2)
for i in range(3,100000,2): #從3開始,跳過偶數(shù)
for j in range(2,int(i**0.5+1)):
if i%j == 0:
break
#else:
#print(i)
stop = datetime.datetime.now()
print(stop-start)
運(yùn)行結(jié)果:0:00:00.406024,又快了不少。
再次優(yōu)化:
可以思考:在第一個for循環(huán)中已經(jīng)將跳過了所有的偶數(shù),在if i%j == 0:語句中i只有奇數(shù),而在數(shù)學(xué)中任何奇數(shù)除以偶數(shù)是一定除不盡的,也就數(shù)說當(dāng)j為偶數(shù)時,語句i%j == 0:一定是為假的。所以可以將j中的偶數(shù)也去掉:
#求10萬以內(nèi)的素數(shù)
import datetime
start = datetime.datetime.now()
print(2)
for i in range(3,100000,2): #從3開始,跳過偶數(shù)
for j in range(3,int(i**0.5+1),2): #再將j的偶數(shù)去掉
if i%j == 0:
break
#else:
#print(i)
stop = datetime.datetime.now()
print(stop-start)
運(yùn)行結(jié)果:0:00:00.271016,比之前的有快了20毫秒。
再三優(yōu)化:
用列表的方式進(jìn)行算法再優(yōu)化。思路是將每次i循環(huán)后如果得到的i是素數(shù)則將它累加到一個列表中,并使j在for循環(huán)中以這個列表為可迭代對象進(jìn)行迭代循環(huán),因?yàn)榱斜碇兴械脑囟际撬財?shù),所以j如果迭代到小于等于i^0.5次方時沒有能整除的數(shù),說明大于i^0.5次方時也沒有能整除的,即此時的i就是素數(shù)。這里也用到了一個數(shù)學(xué)原理:一個數(shù)如果能被小于它的素數(shù)整除則它一定是一個合數(shù),反之它一定是一個素數(shù)。
import datetime
start = datetime.datetime.now()
n = 100000
lst = []
flag = True
#print(2)
for i in range(3,n,2):
up = i**0.5
for j in lst:
if j > up:
flag = True
break
if i % j ==0:
flag = False
break
if flag:
#print(i)
lst.append(i)
stop = datetime.datetime.now()
print(stop-start)
運(yùn)行結(jié)果:0:00:00.177010,又快了!
其它優(yōu)化方案:
優(yōu)化方向:
1.孿生素數(shù)對猜想:大于等于5的素數(shù)一定與6的倍數(shù)相鄰。
2.在奇數(shù)中在排除5的倍數(shù)。
總結(jié)
以上是生活随笔為你收集整理的埃拉托色尼素数筛选法的证明及原理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 实现伪静态页的方法
- 下一篇: 【Hadoop报错】The direct