轮筛 - 从bitsets缓慢重建

时间:2015-12-28 01:39:55

标签: clojure parallel-processing primes

我正试图通过实施一个用于填料的砂轮来进行平行加工,操作顺序大致如下,

  1. 给出一些上限N,构造8个不同的形式辐条 {p, p + 30, p+ 60, ..., p + 30n]中的p {{1, 7, 11, 13, 17, 19, 23, 29}
  2. 将这些全部合并为一个列表
  3. 对于每个p,筛选在步骤2中创建的列表中的所有素数(使用pmap)
  4. 获取这8个位集,解析它们,并重建一些小于N的所有素数的排序列表
  5. 我的代码如下所示(primesprimes2分别是简单筛子和轮筛的单线程实现,用于比较)

    我遇到的问题是,我目前尝试执行第4步(在函数primes4primes5primes6中)都是主导步骤1-3。 任何人都可以给我任何指示我应该如何完成primes3(仅执行步骤1-3)?否则,如果这是绝望的,有人可以解释一些其他策略,将单独的线程分开工作分开吗?

    (defn spoke-30 [p N]
      (map #(+ p (* %1 30)) (range 0 (/ N 30))))
    
    (defn interleaved-spokes
      "returns all the spoke30 elements less than or equal to N (but not the first which is 1)"
      [N]
      (rest (filter #(< % N) (apply interleave (map #(spoke-30 % N) '(1 7 11 13 17 19 23 29))))))
    
    
    (defn get-orbit
      "for a spacing diff, generates the orbit of diff under + in Z_{30}"
      [diff]
      (map #(mod (* diff %) 30) (range 0 30)))
    
    (defn _all-orbits
      "returns a map of maps where each key is an element of (1 7 11 13 17 19 23 29),
      and each value is the orbit of that element under + in Z_30)"
      []
      (let [primes '(1 7 11 13 17 19 23 29)]
        (zipmap primes (map #(zipmap (get-orbit %) (range 30 0 -1)) primes))))
    
    (def all-orbits (memoize _all-orbits))
    
    (defn start 
    "for a prime N and a spoke on-spoke, determine the optimal starting point"
      [N on-spoke]
      (let [dist   (mod (- N) 30)
            lowest (* (((all-orbits) dist) on-spoke) N)
            sqrN (* N N)]
    
        ; this might be one away from where I need to be, but it is a cheaper
        ; calculation than the absolute best start.
        (cond (>= lowest sqrN) lowest
              (= lowest N)  (* 31 N)
              true (+ lowest (* N 30 (int (/ N 30)))))))
    
    (defn primes2 [bound]
      (let [bset      (new java.util.BitSet bound)
            sqrtBound (Math/sqrt bound)
            pList     (interleaved-spokes sqrtBound)]
        (.flip bset 2 bound)
        (doseq [i (range 9 bound 6)] (.clear bset i)) ;clear out the special case 3s
        (doseq [i (range 25 bound 10)] (.clear bset i)) ;clear out the special case 5s
        (doseq [x '(1 7 11 13 17 19 23 29)
                y pList
                z (range (start y x) bound (* 30 y))]
              (.clear bset z))
        (conj (filter (fn [x] (.get bset x)) (range 1 bound 2)) 2)))
    
    
    
    (defn scaled-start [N on-spoke]
      (let [dist      (mod (- N) 30)
            k         (((all-orbits) dist) on-spoke)
            lowest    (int (/ (* k N) 30))
            remaining (* (int (/ (- N k) 30)) N)
            start     (+ lowest remaining)]
        (if (> start 0) start N)))
    
    ;TODO do I even *need* this bitset!?? ...
    (defn mark-composites [bound spoke pList]
      (let [scaledbound  (int (/ bound 30))
            bset         (new java.util.BitSet scaledbound)]
        (if (= spoke 1) (.set bset 0)) ; this won't be marked as composite - but it isn't prime!
        (doseq [x pList
                y (range (scaled-start x spoke) scaledbound x)]
          (.set bset y))
        [spoke bset]))
    
    
    ;TODO now need to find a quick way of reconstructing the required list
    ; need the raw bitsets ... will then loop over [0 scaledbound] and the bitsets, adding to a list in correct order if the element is true and not present already (it shouldn't!)
    (defn primes3 [bound]
      (let [pList (interleaved-spokes (Math/sqrt bound))]
            (pmap #(mark-composites bound % pList) '(1 7 11 13 17 19 23 29)))) 
    
    (defn primes4 [bound]
      (let [pList (interleaved-spokes (Math/sqrt bound))
            bits  (pmap #(mark-composites bound % pList) '(1 7 11 13 17 19 23 29))
            L     (new java.util.ArrayList)]
        (.addAll L '(2 3 5))
        (doseq [z (range 0 (int (/ bound 30))) [x y] bits ]
          (if (not (.get y z)) (.add L (+ x (* 30 z))))
            (println x y z L)
        )))
    
    (defn primes5 [bound]
      (let [pList (interleaved-spokes (Math/sqrt bound))
        bits  (pmap #(mark-composites bound % pList) '(1 7 11 13 17 19 23 29))]
        (for [z (range 0 (int (+ 1 (/ bound 30)))) [x y] bits ]
          (if (not (.get y z)) (+ x (* 30 z))))
        ))
    
    (defn primes6 [bound]
      (let [pList (interleaved-spokes (Math/sqrt bound))]
        (concat '(2 3 5) (filter #(not= % 0) (apply interleave (pmap #(mark-composites2 bound % pList) '(1 7 11 13 17 19 23 29))))))) 
    
    
    (defn primes [n]
      "returns a list of prime numbers less than or equal to n"
      (let [bs (new java.util.BitSet n)]
        (.flip bs 2 n)
        ;(doseq [i (range 4 n 2)] (.clear bs i)) ;clear out the special case 2s
        (doseq [i (range 3 (Math/sqrt n))] 
          (if (.get bs i) ; it seems faster to check if odd than to range in steps of 2
            (doseq [j (range (* i i) n (* 2 i))] (.clear bs j))))
        (conj (filter (fn [x] (.get bs x)) (range 1 n 2)) 2)))
    

    一些时间是:

    user=> (time (count (primes 1000000)))
    "Elapsed time: 117.023543 msecs"
    78498
    user=> (time (count (primes2 1000000)))
    "Elapsed time: 77.10944 msecs"
    78498
    user=> (time (count (primes3 1000000)))
    "Elapsed time: 22.447898 msecs"
    8
    user=> (time (count (primes4 1000000)))
    "Elapsed time: 647.586234 msecs"
    78506
    user=> (time (count (primes5 1000000)))
    "Elapsed time: 721.62017 msecs"
    266672
    user=> (time (count (primes6 1000000)))
    "Elapsed time: 306.280182 msecs"
    

0 个答案:

没有答案