Python 中素數的玩法

Python 中素數的玩法 Python 中素數的玩法 Python 中素數的玩法

質數

質數又稱素數。指整數在一個大於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個;
這樣的分佈說明了什麼?均勻分佈?你們確定不會相信的,我也不信,那彷佛就只能是巧合了。你們必定也會認爲是這純屬巧合。素數嘛,飄忽不定,怎麼分佈都有可能,但就是沒有規律。至少你們尚未發現其分佈規律。算法

打印質數

打印100之內的質數

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

繼續優化,大於2的偶數都不是質數

因此對於偶數都不用判斷是否是素數,修改步長區塊鏈

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循環

第二層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之內的數據...用了40scode

方法二

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),效率會低,修改下方案

修改if and 結構

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 還能夠哈哈

質數相關的理論

  • 哥德巴赫猜測:任何大於5的奇數都是三個素數之和
  • 衍生:任何一個大於2的偶數都是兩個素數之和
  • 伯特蘭猜測:對於任意正整數n>1,存在一個素數p,使得n<p<2n
  • 孿生素數猜測:存在無窮多的形如p和p+2的素數對
  • n2+1 猜測:存在無窮多個形如n2+1的素數,其中n是正整數

量子計算機,瞭解一下......密碼學、區塊鏈都將被從新定義~

相關文章
相關標籤/搜索