我正在编写一个Common Lisp函数来打印前N个素数。到目前为止,我已经成功地编写了以下代码:
;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编写代码。
更新:
(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。
发布于 2013-04-05 01:26:59
首先,这里根本不需要使用全局变量。
使用true/false返回值。这将允许您的is-prime函数类似于:
(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函数,使其不使用全局变量。
第四,永远不要使用setf或setq创建全局变量,使用defvar or defparameter中的任何一个。在您的全局(实际上是“特殊的”)变量上使用*earmuffs*也是一种很好的风格(大多数情况下,但也有一些人不同意)。
发布于 2013-04-05 16:04:09
要对Vatines进行扩展,请回答:
使用相同的算法但避免全局参数的prime-numbers函数的可能重写是
(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值,可能会耗尽堆栈空间。
一个非递归变体是
(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)))https://stackoverflow.com/questions/15817350
复制相似问题