Scheme 从prime sieve函数返回向量(固定长度数组),然后将其转换为list

Scheme 从prime sieve函数返回向量(固定长度数组),然后将其转换为list,scheme,Scheme,我发现了一个prime sieve函数,它使用Eratosthenes的sieve来计算第一个n素数。该方法基于Donald Knuth的算法,我将其复制自: 不幸的是,我不确定第一个函数是否返回向量,因为(vector?(prime sieve 1000))返回f。当我运行下面的代码并尝试查看前1000个素数的列表时: (sieve-to-list (prime-sieve 1000) 1000) 我得到一个错误: 向量引用:合同违反预期:向量?给定:#t参数位置:第一个其他参数…: 如果我

我发现了一个
prime sieve
函数,它使用Eratosthenes的sieve来计算第一个
n
素数。该方法基于Donald Knuth的算法,我将其复制自:

不幸的是,我不确定第一个函数是否返回向量,因为
(vector?(prime sieve 1000))
返回f。当我运行下面的代码并尝试查看前1000个素数的列表时:

(sieve-to-list (prime-sieve 1000) 1000)
我得到一个错误:

向量引用:合同违反
预期:向量?
给定:#t
参数位置:第一个
其他参数…:

如果我将
prime sieve
中的#t更改为在“给定”之后显示的其他内容

我对向量知之甚少。如果筛子不返回向量,为什么它不返回向量?我如何使它返回向量?如果它确实返回一个向量,为什么我的转换函数不起作用呢?

您链接的代码打印素数,但不存储它们或以任何方式返回它们。要存储它们,应该使用累加器技术,就像在
筛选列表中一样。无论如何,这里有一个固定版本(我也借此机会清理了很多代码):

这将返回一个列表,而不是向量。这是因为结果是以增量方式构建的,而列表对结果有利,而向量则不然

我通过将结果与测试结果进行比较来验证上述代码


你用球拍吗?我注意到您在代码中使用了
add1
。如果是这样,这里的算法是相同的,但在Racket中使用
进行理解,这更简洁、更容易阅读:

(define (prime-sieve n)
  (define vec (make-vector (add1 n) #t))
  (define (eradicate! p q)
    (do ((q q (+ q p)))
        ((> q n))
      (vector-set! vec q #f)))
  (cons 2 (for/list ((j (in-range 1 (add1 n)))
                     #:when (vector-ref vec j))
            (define p (+ j j 1))
            (eradicate! p (* 2 j (add1 j)))
            p)))
在这个版本中,
p
q
每次都从
j
重新计算,而不是累加,但我认为这不是一个大问题。

您链接的代码打印素数,但不存储它们或以任何方式返回它们。要存储它们,应该使用累加器技术,就像在
筛选列表中一样。无论如何,这里有一个固定版本(我也借此机会清理了很多代码):

这将返回一个列表,而不是向量。这是因为结果是以增量方式构建的,而列表对结果有利,而向量则不然

我通过将结果与测试结果进行比较来验证上述代码


你用球拍吗?我注意到您在代码中使用了
add1
。如果是这样,这里的算法是相同的,但在Racket中使用
进行理解,这更简洁、更容易阅读:

(define (prime-sieve n)
  (define vec (make-vector (add1 n) #t))
  (define (eradicate! p q)
    (do ((q q (+ q p)))
        ((> q n))
      (vector-set! vec q #f)))
  (cons 2 (for/list ((j (in-range 1 (add1 n)))
                     #:when (vector-ref vec j))
            (define p (+ j j 1))
            (eradicate! p (* 2 j (add1 j)))
            p)))
在这个版本中,
p
q
每次都从
j
重新计算,而不是累加,但我认为这不是一个大问题。

您链接的代码打印素数,但不存储它们或以任何方式返回它们。要存储它们,应该使用累加器技术,就像在
筛选列表中一样。无论如何,这里有一个固定版本(我也借此机会清理了很多代码):

这将返回一个列表,而不是向量。这是因为结果是以增量方式构建的,而列表对结果有利,而向量则不然

我通过将结果与测试结果进行比较来验证上述代码


你用球拍吗?我注意到您在代码中使用了
add1
。如果是这样,这里的算法是相同的,但在Racket中使用
进行理解,这更简洁、更容易阅读:

(define (prime-sieve n)
  (define vec (make-vector (add1 n) #t))
  (define (eradicate! p q)
    (do ((q q (+ q p)))
        ((> q n))
      (vector-set! vec q #f)))
  (cons 2 (for/list ((j (in-range 1 (add1 n)))
                     #:when (vector-ref vec j))
            (define p (+ j j 1))
            (eradicate! p (* 2 j (add1 j)))
            p)))
在这个版本中,
p
q
每次都从
j
重新计算,而不是累加,但我认为这不是一个大问题。

您链接的代码打印素数,但不存储它们或以任何方式返回它们。要存储它们,应该使用累加器技术,就像在
筛选列表中一样。无论如何,这里有一个固定版本(我也借此机会清理了很多代码):

这将返回一个列表,而不是向量。这是因为结果是以增量方式构建的,而列表对结果有利,而向量则不然

我通过将结果与测试结果进行比较来验证上述代码


你用球拍吗?我注意到您在代码中使用了
add1
。如果是这样,这里的算法是相同的,但在Racket中使用
进行理解,这更简洁、更容易阅读:

(define (prime-sieve n)
  (define vec (make-vector (add1 n) #t))
  (define (eradicate! p q)
    (do ((q q (+ q p)))
        ((> q n))
      (vector-set! vec q #f)))
  (cons 2 (for/list ((j (in-range 1 (add1 n)))
                     #:when (vector-ref vec j))
            (define p (+ j j 1))
            (eradicate! p (* 2 j (add1 j)))
            p)))

在这个版本中,
p
q
每次都从
j
重新计算,而不是累加,但我认为这不是一个大问题。

我使用的是
#lang scheme
。谢谢你的回答。这使它更具可读性你说在这种情况下,生成一个列表比生成一个向量更好,但是因为我必须在筛子中查找素数,这比生成列表(仅一次)要多一百万次,所以有必要返回一个数组/向量。列表中的查找速度太慢。是否可以返回向量而不是列表?只需在列表上使用
list->vector
就足够快了。:-)谢谢你的帮助!注意你的筛子漏掉了质数2。@ErwinRooijakkers很高兴你喜欢。是的,以后使用
list->vector
转换为vector(最好自己做,而不是让原来的函数做)。(在我的答案中链接)确实放入了2,但社区计划Wiki 1(您复制的,我为这个答案改编的,主要是为了向您展示我将如何重构它)没有,所以我编辑了它,将其也放入了2中。:-)@ErwinRooijakkers如果你在这篇文章中谈论的是
素数筛
,它会返回2n以下的所有素数。它不返回n个素数;目前还没有有效的方法来实现这一点(至少,不是基于埃拉托斯烯的筛选)。偶数被命名为
素数最多约为
,原因是:n指定了搜索的上限,而不是素数的数量。我使用
#lang scheme
。谢谢你的回答。这使它更具可读性你说最好是