这很无聊,我知道,但我需要一些帮助来理解Eratosthenes筛子的实施。这是this Programming Praxis problem的解决方案。
(define (primes n)
(let* ((max-index (quotient (- n 3) 2))
(v (make-vector (+ 1 max-index) #t)))
(let loop ((i 0) (ps '(2)))
(let ((p (+ i i 3)) (startj (+ (* 2 i i) (* 6 i) 3)))
(cond ((>= (* p p) n)
(let loop ((j i) (ps ps))
(cond ((> j max-index) (reverse ps))
((vector-ref v j)
(loop (+ j 1) (cons (+ j j 3) ps)))
(else (loop (+ j 1) ps)))))
((vector-ref v i)
(let loop ((j startj))
(if (<= j max-index)
(begin (vector-set! v j #f)
(loop (+ j p)))))
(loop (+ 1 i) (cons p ps)))
(else (loop (+ 1 i) ps)))))))
我遇到问题的部分是startj
。现在,我可以看到p
将从3开始循环通过奇数,定义为(+ i i 3)
。但我不理解p
和startj
之间的关系,即(+ (* 2 i i) (* 6 i) 3)
。
编辑:我知道这个想法是跳过以前过筛的数字。拼图定义指出,在筛选数字x
时,筛选应从x
的平方开始。所以,当筛选3时,首先要消除9等等。
但是,我不明白的是作者如何为startj
(代数)提出这个表达式。
从拼图评论:
一般来说,当筛选n时,筛选开始于n平方,因为所有先前的n倍已经过筛。
表达式的其余部分与数字和筛选索引之间的交叉引用有关。表达式中有2个,因为我们在开始之前消除了所有偶数。表达式中有3个因为Scheme向量是从零开始的,而数字0,1和2不是筛子的一部分。我认为6实际上是2和3的组合,但是我看了代码已经有一段时间了,所以我会留给你弄清楚。
如果有人能帮助我,那就太好了。谢谢!
答案 0 :(得分:4)
我认为在programpraxis'comments on their website的帮助下我已经弄明白了。
要重述此问题,startj
在列表中定义为(+ (* 2 i i) (* 6 i) 3)
,即2i^2 + 6i + 3
。
我最初没有理解这个表达式与p
的关系 - 因为“{1}}号码的'筛选'应该从p
开始,我认为p^2
应该startj
与4i^2 + 12i + 9
有关。
但是,startj
是向量v
的索引,它包含从3开始的奇数。因此,p^2
的索引实际上是(p^2 - 3) / 2
。
扩展等式:(p^2 - 3) / 2
= ([4i^2 + 12i + 9] - 3) / 2
= 2i^2 + 6i + 3
- 这是startj
的值。
我觉得将startj
定义为(quotient (- (* p p) 3) 2)
可能会更清楚,但无论如何 - 我认为可以解决它:)
答案 1 :(得分:3)
Ephemient:正确。
请在Programming Praxis的评论中查看更完整的说明。
编辑:我在Programming Praxis上添加了一条评论。当我真正查看代码时,我错误地推导出公式中的数字6;抱歉,我误导了你。