我正在制作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。
答案 0 :(得分:6)
首先,根本不需要在这里使用全局变量。
使用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
(可能)是函数的返回值。
要检查,请尝试: (预测(素数10)无)
第三,重新编写prime-numbers
函数以不使用全局变量。
第四,永远不要使用setf
或setq
创建全局变量,使用defvar
or defparameter
。在你的全局(真正的,“特殊”)变量上使用*earmuffs*
也是(大多数,但有些不同意)好的风格。
答案 1 :(得分:3)
扩展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)))))
此函数也会返回素数而不是打印它们。
这种递归解决方案的问题是它为每个找到/测试的素数消耗了堆栈。因此,对于较大的数值,可能会耗尽堆栈空间
非递归变体是
(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)))