首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用Common Lisp打印前N个素数

用Common Lisp打印前N个素数
EN

Stack Overflow用户
提问于 2013-04-05 01:03:30
回答 2查看 6.4K关注 0票数 1

我正在编写一个Common Lisp函数来打印前N个素数。到目前为止,我已经成功地编写了以下代码:

代码语言:javascript
复制
;globals 
(setf isprime 1) ;if 1 then its a prime, 0 if not.
(setf from 1)    ;start from 1
(setf count 0)   ;should act as counter to check if we have already 
                 ;    N primes printed

;function so far.
(defun prime-numbers (to)
  (if (> count to) nil(progn
      (is-prime from from)
      (if (= isprime 1) (print from)(setf count (+ count 1)))
      (setf isprime 1)
      (setf from (+ from 1))
      (prime-numbers to)))
  (if (>= count to)(setf count 0) (setf from 1)))  

;code to check if a number is prime    
(defun is-prime(num val)
  (if (< num 3) nil 
    (progn
      (if (= (mod val (- num 1)) 0) (setf isprime 0))
      (is-prime (- num 1) val))))

我的问题是,它不能正确地打印N个素数。如果我调用>(prime-numbers 10),结果是:1 2 3 5 7 11 13 17 19 1,即它只正确打印了9个素数。

但是如果我调用>(prime-numbers 2),结果是:1 2 3 5 7 1

我到底做错了什么?这是我第一次用LISP编写代码。

更新:

代码语言:javascript
复制
  (defparameter from 1)
  (defparameter count 0)

  (defun prime-numbers (to)
     (if (> count to)nil
         (progn
            (when (is-prime from) 
                (print from)
                (setf count (+ count 1)))
            (setf from (+ from 1))
            (prime-numbers to)))
     (when (>= count to)
         (setf count 0) 
         (setf from 1)))  

  (defun is-prime (n)
    (cond ((= 2 n) t)
     ((= 3 n) t)
     ((evenp n) nil)
     (t 
       (loop for i from 3 to (isqrt n) by 2
             never (zerop (mod n i))))))

工作正常。但在末尾输出一个NIL。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-04-05 01:26:59

首先,这里根本不需要使用全局变量。

使用true/false返回值。这将允许您的is-prime函数类似于:

代码语言:javascript
复制
(defun is-prime (n)
  (cond ((= 2 n) t) ;; Hard-code "2 is a prime"
        ((= 3 n) t) ;; Hard-code "3 is a prime"
        ((evenp n) nil) ;; If we're looking at an even now, it's not a prime
        (t ;; If it is divisible by an odd number below its square root, it's not prime
           (loop for i from 3 to (isqrt n) by 2
                 never (zerop (mod n i))))))

这样,函数就不依赖于任何外部状态,也不会有任何混淆。

其次,您看到的最后一个1 (可能)是函数的返回值。

要检查这一点,请尝试:(progn (prime-numbers 10) nil)

第三,重写prime-numbers函数,使其不使用全局变量。

第四,永远不要使用setfsetq创建全局变量,使用defvar or defparameter中的任何一个。在您的全局(实际上是“特殊的”)变量上使用*earmuffs*也是一种很好的风格(大多数情况下,但也有一些人不同意)。

票数 7
EN

Stack Overflow用户

发布于 2013-04-05 16:04:09

要对Vatines进行扩展,请回答:

使用相同的算法但避免全局参数的prime-numbers函数的可能重写是

代码语言:javascript
复制
(defun prime-numbers (num &optional (from 2))
   (cond ((<= num 0) nil)
         ((is-prime from) (cons from (prime-numbers (1- num) (1+ from))))
         (t (prime-numbers num (1+ from)))))

此函数还返回素数,而不是打印它们。

这种递归解决方案的问题是,它会消耗找到/测试的每个素数的堆栈。因此,对于较大的num值,可能会耗尽堆栈空间。

一个非递归变体是

代码语言:javascript
复制
(defun prime-numbers (num &optional (start 2))
   (loop for n upfrom start
         when (is-prime n)
         sum 1 into count
         and collect n
         until (>= count num)))
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15817350

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档