Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何提高我的eratosthenes算法clojure筛的性能?_Clojure_Lisp_Sieve Of Eratosthenes - Fatal编程技术网

如何提高我的eratosthenes算法clojure筛的性能?

如何提高我的eratosthenes算法clojure筛的性能?,clojure,lisp,sieve-of-eratosthenes,Clojure,Lisp,Sieve Of Eratosthenes,我通过euler项目学习clojure,并且正在解决第10个问题(找出所有素数之和低于200万。我为eratosthenes筛实现了一个相当文字化的算法,但它的工作速度太慢,无法用于多达200万个素数。我尝试使用loop recur实现它,以不创建任何新帧,但这对性能没有太大影响 (defn find-primes-sum [last-prime nums] (loop [p last-prime n nums sum 0] (println p) (if

我通过euler项目学习clojure,并且正在解决第10个问题(找出所有素数之和低于200万。我为eratosthenes筛实现了一个相当文字化的算法,但它的工作速度太慢,无法用于多达200万个素数。我尝试使用loop recur实现它,以不创建任何新帧,但这对性能没有太大影响

(defn find-primes-sum [last-prime nums]
    (loop [p last-prime n nums sum 0]
        (println p)
        (if (empty? n)
        sum
            (recur (first n) (doall (remove #(zero? (mod % (first n))) n)) (+ sum (first n))))))

(defn sieve-primes-until [limit]
    (find-primes-sum 2 (filter odd? (range 2 (inc limit)))))

(println (sieve-primes-until 2000000))

就我个人而言,我会以不同的方式构造代码。我已经实现了这个问题,首先生成所有素数的惰性序列,然后对前2000000项求和。在clojure 1.2上需要16秒,但除了使用recur,它几乎没有得到优化

你还做了很多不必要的与输入范围的比较;
(remove#(zero)(mod%(first n)))n
根据所有奇数测试所有候选数,这是毫无意义的**,特别是当你用doall强制它时。你实际上只需要根据所有已知的素数测试候选素数
x
(设置!*未选中数学*为真) (定义宏iloop[[b t n]和正文] `(循环[~@b] (当~t ~@体 (重现~n))) (定义计数素数[^long n] (让[c(inc n) ^布尔素数?(使数组为布尔值/类型c)]
(iloop[(i 2)(抽象从外观上看是好的,有利于优化。编写更小更好的函数比优化复杂函数更直观。正如@Joost Diepenmaat所说,至少要将素数生成和求和分开。不过,不要过多地讨论这个特定问题。有些人为他们的博士学位编写了sieve algo!我不确定你是否你知道代码试图做什么(应该已经注释了!)。当它递归时,数字的范围被替换为一个已经删除了最后一个素数的所有倍数的范围,因为这些显然不是素数或是有用的因子。
doall
是用来强制计算
remove#(零?(mod%(first n)))n)
以防止惰性导致堆栈溢出。另一个注意事项是,如果我重新编写它以查找给定所有先前数字的下一个素数,我需要测试该范围内的每个数字,或者是否有方法限制我需要测试的数字(显然,除了使用只有偶数的范围外)我想我确实理解,但就我所见,这样做算法意味着要做更多的可分性测试,因为你从一个庞大的候选列表开始,然后慢慢剔除。如果你定义一个素数X是一个所有素数都不可分的数,那么你的第二个问题是:你只需要测试以前的素数。在本页的相关部分有几个问题,你可能会发现有趣的。
(set! *unchecked-math* true)

(defmacro iloop [[b t n] & body]
  `(loop [~@b]
     (when ~t
       ~@body
       (recur ~n))))

(defn count-primes [^long n]
  (let [c (inc n)
        ^booleans prime? (make-array Boolean/TYPE c)]
    (iloop [(i 2) (<= i n) (inc i)]
      (aset prime? i true))
    (iloop [(i 2) (<= (* i i) n) (inc i)]
      (if (aget prime? i)
        (iloop [(j i) (<= (* i j) n) (inc j)]
          (aset prime? (* i j) false))))
    (areduce prime? i r 0
      (if (aget prime? i)
        (inc r)
        r))))