[英]Is this an optimal prime generator?
這在任何方面都是尋找素數的最佳解決方案嗎? 我不是想在陽光下添加所有優化,但主要的好處是什么?
def primesUpto(self, x):
primes = [2]
sieve = [2]
i = 3
while i <= x:
composite = False
j = 0
while j < len(sieve):
sieve[j] = sieve[j] - 1
if sieve[j] == 0:
composite = True
sieve[j] = primes[j]
j += 1
if not composite:
primes.append(i)
sieve.append(i*i-i)
i += 1
return primes
嗯,非常有趣。 你的代碼對於Eratosthenes恕我直言的善良真正的篩子是真實誠實的,通過減少它為每個遇到的每個素數設置的每個計數器來計算其上升的自然數,每步1。
這是非常低效的。 在Ideone上進行測試,它以相同的經驗增長順序運行~ n^2.2
(在測試的幾千個質數范圍內)作為着名的低效特納試驗分區篩 (在Haskell中)。
為什么? 幾個原因。 首先 ,你的測試沒有提前救助 :當你發現它是復合材料時,你繼續處理計數器陣列, sieve
。 你必須這樣做,因為第二個原因 :你通過在每一步減少每個計數器1來計算差值,0代表你當前的位置。 這是原始篩選IMHO最忠實的表達,效率非常低:今天我們的CPU知道如何在O(1)時間內添加數字(如果這些數字屬於某個范圍,0 .. 2 ^ 32,或者0 .. 2 ^ 64,當然)。
此外,我們的計算機現在也有直接訪問內存,並且計算了遠程數,我們可以在隨機訪問數組中標記它。 這是Eratosthenes篩在現代計算機上的效率的基礎 - 直接計算和倍數的直接標記。
第三 ,也許是效率低下的最直接原因,是對於倍數的過早處理:當你遇到5作為素數時,你將其第一個倍數(尚未遇到),即25, 立即加入計數器陣列, sieve
(即當前點與倍數之間的距離, i*ii
)。 那太早了。 25的加法必須推遲到......好吧,直到我們在升序的自然數中遇到25。 開始過早地處理每個素數的倍數(在p
而不是p*p
)導致有太多的計數器要維持 - 它們的O(n)
(其中n
是產生的素數的數量),而不是僅僅O(π(sqrt(n log n))) = O(sqrt(n / log n))
。
當應用於Haskell中類似的“計數”篩子時 , 推遲優化使其經驗的增長順序從~ n^2.3 .. 2.6
對於n = 1000 .. 6000
數下降到略高於~ n^1.5
(顯着的巨大收益)速度)。 當計數進一步被直接加法取代時,得到的經驗增長的經驗順序為~ n^1.2 .. 1.3
,產生高達一百萬個質數(盡管很可能它會在更大的范圍內獲得~ n^1.5
)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.