【发布时间】:2012-07-26 00:43:15
【问题描述】:
以下代码生成从 1 到 n 的素数:
(defun prime-list(n)
(let ((a)(b)(x (floor (sqrt n))))
(loop for i from (floor n 6) downto 1 do
(push (1+ (* 6 i)) a)
(push (1- (* 6 i)) a))
(loop while (<= (car a) x) do
(push (car a) b)
(setf a (remove-if #'(lambda(m)(or (= 0 (mod m (car a))) (> m n))) a)))
(append '(2 3) (reverse b) a)))
在我看来这部分
(setf a (remove-if #'XXX a))
可以替换为
(delete-if #'XXX a)
我希望这会使其更快。但是,当我进行更改时,函数现在进入无限循环并且永远不会返回。为什么?
【问题讨论】:
-
ERROR1: 应该是
while (<= (car a) x)ERROR2: 因为任何素数的形式都是6i+-1,所以任何素数的平方模 6 为 1。如果n == p^2-1对于一些素数p,它遵循n == 6i对于一些i。 Q 中的代码会将6i+1 == p^2包含在列表中;但将通过x = sqrt(n) < p进行测试,因此将在输出中包含p^2。因此,当使用n=p^2-1调用任何素数时,以上将产生p^2作为其输出中的最后一个elt。 (我不编辑这个,因为 Q 不是关于代码的有效性)。 -
另外,这是一个试验除法筛,它的效率远低于 Eratosthenes 的筛(它以相等的增量计数以找到倍数,而不是通过师)。
-
@WillNess TURE。我正在玩这个并且没有考虑效率。后来我使用了bit-array,你可以在这里找到代码:rosettacode.org/wiki/Sieve_of_Eratosthenes#Common_Lisp(第2个,欢迎评论。)
-
明白。我只是为了方便读者而注意到这一点。 (error1 现已修复;error2 仍然存在)。
-
@WillNess 已更改。但这可能不是修复它的最佳方法。 ;)
标签: lisp common-lisp primes