簡體   English   中英

是否有一個快速的、功能性的素數生成器?

[英]Is there a fast, functional prime generator?

假設我有一個自然數n並且我想要一個直到n的所有素數的列表(或其他)。

經典的素數篩選算法在O(n log n)時間和O(n)空間中運行——它適用於更多命令式語言,但需要以基本方式對列表和隨機訪問進行就地修改。

有一個涉及優先級隊列的功能版本,它非常巧妙——您可以在此處查看 這在大約O(n / log(n))具有更好的空間復雜度(漸近更好但在實際規模上有爭議)。 不幸的是,時間分析很糟糕,但它非常接近O(n^2) (實際上,我認為它是關於O(n log(n) Li(n)) ,但log(n) Li(n)大約是n ) .

漸近地說,使用連續試除法在生成每個數字時檢查它的素性實際上會更好,因為這將只需要O(1)空間和O(n^{3/2})時間。 有沒有更好的辦法?

編輯:事實證明我的計算完全不正確。 文章中的算法是O(n (log n) (log log n)) ,文章對此進行了解釋和證明(並參見下面的答案),而不是我上面提出的復雜混亂。 如果有一個真正的O(n log log n)純算法,我仍然會喜歡。

這是 Melissa O'Neill 算法的 Haskell 實現(來自鏈接文章)。 與 Gassa 鏈接的實現不同,我很少使用懶惰,因此性能分析很清楚—— O(n log n log log n) ,即,n log log n 中的線性,寫入次數通過 Eratosthenes 的命令式篩選。

堆實現只是一個錦標賽樹。 平衡邏輯正在push 通過每次交換子節點,我們確保對於每個分支,左子樹的大小與右子樹相同或大一倍,從而確保深度 O(log n)。

module Sieve where

type Nat = Int

data Heap = Leaf !Nat !Nat
          | Branch !Nat !Heap !Heap
          deriving Show

top :: Heap -> Nat
top (Leaf n _) = n
top (Branch n _ _) = n

leaf :: Nat -> Heap
leaf p = Leaf (3 * p) p

branch :: Heap -> Heap -> Heap
branch h1 h2 = Branch (min (top h1) (top h2)) h1 h2

pop :: Heap -> Heap
pop (Leaf n p) = Leaf (n + 2 * p) p
pop (Branch _ h1 h2)
  = case compare (top h1) (top h2) of
        LT -> branch (pop h1) h2
        EQ -> branch (pop h1) (pop h2)
        GT -> branch h1 (pop h2)

push :: Nat -> Heap -> Heap
push p h@(Leaf _ _) = branch (leaf p) h
push p (Branch _ h1 h2) = branch (push p h2) h1

primes :: [Nat]
primes
  = let helper n h
          = case compare n (top h) of
                LT -> n : helper (n + 2) (push n h)
                EQ -> helper (n + 2) (pop h)
                GT -> helper n (pop h)
      in 2 : 3 : helper 5 (leaf 3)

在這里,如果(Haskell 的)純數組算作純數組(他們應該,IMO)。 復雜性顯然是O(n log (log n)) ,前提是accumArray確實為給定的每個條目花費了O(1)時間,因為它應該:

import Data.Array.Unboxed 
import Data.List (tails, inits)

ps = 2 : [ n | (r:q:_, px) <- (zip . tails . (2:) . map (^2)) ps (inits ps),
               (n,True)    <- assocs (
                                accumArray (\_ _ -> False) True (r+1,q-1)
                                  [(m,()) | p <- px, let s = (r+p)`div`p*p, 
                                            m <- [s,s+p..q-1]] :: UArray Int Bool) ]

按連續素數平方之間的段( map (^2)位)計算素數,通過枚舉不斷增長的素數前綴( inits位)的倍數來生成復合,就像任何適當的 Eratosthenes 篩子一樣,通過重復添加。

因此,素數{2,3}用於篩選從1024的段; {2,3,5}2648 等等。 另見

此外,基於 Python 生成器的篩選器也可能被認為是功能性的。 根據經驗,Python 的dict非常好,盡管我不確定在那里使用的倍數過度生產方案的確切成本,以避免重復組合。


更新:正如預期的那樣,測試它確實產生了有利的結果:

{-     original heap       tweaked           nested-feed         array-based
          (3*p,p)         (p*p,2*p)            JBwoVL              abPSOx
          6Uv0cL          2x speed-up     another 3x+ speed-up
                n^                n^                  n^                  n^
100K:  0.78s             0.38s               0.13s              0.065s    
200K:  2.02s   1.37      0.97s   1.35        0.29s   1.16       0.13s    1.00
400K:  5.05s   1.32      2.40s   1.31        0.70s   1.27       0.29s    1.16
800K: 12.37s   1.29                     1M:  2.10s   1.20       0.82s    1.13
 2M:                                                            1.71s    1.06
 4M:                                                            3.72s    1.12
10M:                                                            9.84s    1.06 
    overall in the tested range:
               1.33                                  1.21                1.09
-}

and O(n log n log log n) as .使用經驗增長順序計算產生n 個素數,其中O(n log log n)通常被視為O(n log n log log n)

in the tested range). "nested-feed"變體實現了延遲技術(也可以在上面鏈接的 Python 答案中看到),它實現了堆大小的二次減小,這顯然對經驗復雜性有顯着影響,即使沒有完全達到更好的結果對於這個答案的基於數組的代碼,它能夠在 ideone.com 上在不到 10 秒的時間內生成1000 萬個素數(在測試范圍內,整體增長率僅為 )。

“原始堆”當然是此處其他答案中的代碼)。

不久前,我導出了一個素數生成函數(按順序生成所有素數)。 還為它創建了一個 6 頁的證明。 我認為它實際上是歷史上第一個素數生成函數(至少我找不到任何其他例子)。

這里是:
在此處輸入圖片說明

(-1)^((4*gamma(x)+4)/x)-1

不確定它可以計算多快。 它為所有素數返回 0(或者它可能是 1,不記得了)。 Gamma 函數本質上是階乘的,因此可以在早期很快。 將負 1 提高到分數指數是另一回事,但我相信它可能使用 base_e 中的積分,或者可能使用一些三角函數; 不記得了。

我不知道 LaTeX 所以如果有人想編輯我的帖子並包含一個很棒的 LaTeX 版本!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM