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
Algorithm 埃拉托什尼的Clojure尾递归筛_Algorithm_Clojure_Functional Programming_Primes_Sieve Of Eratosthenes - Fatal编程技术网

Algorithm 埃拉托什尼的Clojure尾递归筛

Algorithm 埃拉托什尼的Clojure尾递归筛,algorithm,clojure,functional-programming,primes,sieve-of-eratosthenes,Algorithm,Clojure,Functional Programming,Primes,Sieve Of Eratosthenes,我在Clojure实施了Eratosthenes筛: (defn sieve [n] (loop [last-tried 2 sift (range 2 (inc n))] (if (or (nil? last-tried) (> last-tried n)) sift (let [filtered (filter #(or (= % last-tried) (< 0 (rem % last-tried))) sift)]

我在Clojure实施了Eratosthenes筛:

(defn sieve [n]
  (loop [last-tried 2 sift (range 2 (inc n))]
    (if
      (or (nil? last-tried) (> last-tried n))
      sift
      (let [filtered (filter #(or (= % last-tried) (< 0 (rem % last-tried))) sift)]
        (let [next-to-try (first (filter #(> % last-tried) filtered))]
        (recur next-to-try filtered))))))
(defn筛[n]
(循环[上次尝试的2次筛选(范围2(包括n))]
(如果
(或(无?最后一次尝试)(>最后一次尝试n))
筛
(让[筛选(筛选#)(或(=上次尝试百分比)(<0(rem上次尝试百分比)))筛选)]
(让[在try(first(filter#)(>%last Tweed)filtered)旁边])
(在下一步重复尝试过滤((()())))

对于较大的
n
(如20000),它以堆栈溢出结束。为什么尾部呼叫消除在这里不起作用?如何修复它?

如果您查看回溯跟踪

(try
 (sieve 200000)
 (catch java.lang.StackOverflowError e
  (.printStackTrace e)))
看起来是这样的:

...
at clojure.lang.LazySeq.sval(LazySeq.java:42)
at clojure.lang.LazySeq.seq(LazySeq.java:56)
at clojure.lang.RT.seq(RT.java:440)
at clojure.core$seq__4176.invoke(core.clj:103)
at clojure.core$filter__5033$fn__5035.invoke(core.clj:1751)
at clojure.lang.LazySeq.sval(LazySeq.java:42)
at clojure.lang.LazySeq.seq(LazySeq.java:56)
...
导致溢出的是太多的过滤器,而不是循环


不幸的是,我没有看到一个明显的解决方案。

问题:
filter
执行惰性计算,因此每个新的过滤级别都挂在调用堆栈上

修复:将
(过滤器…
更改为
(doall(过滤器…)


请参阅解释。

我支持Michal Marczyk关于检查cgrande美丽的增量SoE的评论。我做了一些非常原始的基准测试,并将它们放在了上,以满足那些对惰性素数生成器性能好奇的人。

作为旁注,但这不是埃拉托什尼的筛子。SoE不执行剩余操作,只执行添加和“删除”。请参阅以获得更广泛的讨论(这是一本很棒的读物!);有关Christophe Grand在Clojure中漂亮的“增量”SoE实现,请参见(这也是我迄今为止看到的最快版本)。@MichałMarczyk谢谢。我想说的是,在这个算法中,“删去”相当于“过滤”,而“加法”相当于“乘法”,因此也相当于“余数”。当然,结果是一样的,但算法的复杂度却大不相同。这篇文章在数学方面做得很好,但不幸的是在解释数学方面做得很差。不同之处在于通过连续增加素数块(前1个、前2个、前3个素数、前4个素数,…)测试复合物的迭代移除,与仅从其素数因子独立生成复合物(
p-->{p*p,p*p+p,p*p+2*p,…}
)之间的区别。线索在LazySeq中。Clojures对懒惰的实现有一些缺陷,这就是其中之一。您已经正确地识别了主要的算法问题(而不仅仅是技术问题)。一个显而易见的解决方案是在不再需要过滤时立即停止过滤。也就是说,当
(>(*last-trued-last-trued)n)
时。对于20000个,这意味着用大约2000个递归深度交换大约30个递归深度(实际上是30对1862个嵌套过滤器)。