【发布时间】:2011-02-28 03:56:42
【问题描述】:
我在 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))))))
对于较大的n(如 20000),它以堆栈溢出结束。为什么尾部呼叫消除在这里不起作用?如何解决?
【问题讨论】:
-
附带说明,但这不是 Eratosthenes 的筛子。 SoE 不执行余数运算,只是加法和“划掉”。请参阅cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf 进行扩展讨论(这是一本很棒的书!);有关 Christophe Grand 在 Clojure 中的漂亮“增量” SoE 实现,请参阅 clj-me.cgrand.net/2009/07/30/…(它也是我迄今为止见过的最快的版本)。
-
@Michał Marczyk 谢谢。我会说“划掉”相当于“过滤”,而这个算法中的“加法”相当于“乘法”,因此相当于“余数”。
-
并非如此。结果当然是一样的,但算法复杂度却大不相同。
-
这篇文章在数学方面非常出色,但不幸的是,在解释数学方面的文字做得很差。区别在于通过连续增加的素数块 (前 1 个、前 2 个、前 3 个素数、前 4 个素数,...) 测试的复合材料的迭代去除与独立生产的复合材料之间的区别仅其主要因素 (
p --> {p*p, p*p+p, p*p+2*p, ...})。
标签: algorithm clojure functional-programming primes sieve-of-eratosthenes