帮助理解Sierat of Eratosthenes的实施

时间:2009-10-20 23:53:32

标签: algorithm scheme puzzle sieve-of-eratosthenes

这很无聊,我知道,但我需要一些帮助来理解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)。但我不理解pstartj之间的关系,即(+ (* 2 i i) (* 6 i) 3)


编辑:我知道这个想法是跳过以前过筛的数字。拼图定义指出,在筛选数字x时,筛选应从x的平方开始。所以,当筛选3时,首先要消除9等等。

但是,我不明白的是作者如何为startj(代数)提出这个表达式。

从拼图评论:

  

一般来说,当筛选n时,筛选开始于n平方,因为所有先前的n倍已经过筛。

     

表达式的其余部分与数字和筛选索引之间的交叉引用有关。表达式中有2个,因为我们在开始之前消除了所有偶数。表达式中有3个因为Scheme向量是从零开始的,而数字0,1和2不是筛子的一部分。我认为6实际上是2和3的组合,但是我看了代码已经有一段时间了,所以我会留给你弄清楚。


如果有人能帮助我,那就太好了。谢谢!

2 个答案:

答案 0 :(得分:4)

我认为在programpraxis'comments on their website的帮助下我已经弄明白了。

要重述此问题,startj在列表中定义为(+ (* 2 i i) (* 6 i) 3),即2i^2 + 6i + 3

我最初没有理解这个表达式与p的关系 - 因为“{1}}号码的'筛选'应该从p开始,我认为p^2应该startj4i^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)

David Seiler:也许不是最清楚的,但除了实现基本的Sieve之外,它还必须实现练习中描述的三个优化。

哈托:那是我的第二次练习。我还在尝试自己的写作风格。

Ephemient:正确。

请在Programming Praxis的评论中查看更完整的说明。

编辑:我在Programming Praxis上添加了一条评论。当我真正查看代码时,我错误地推导出公式中的数字6;抱歉,我误导了你。