我对LISP很新,正在解决一些初学者问题。我尝试定义一个ISPRIME函数,但似乎没有正常工作。这是我的代码:
(defun ISPRIME (n &optional (d (- n 1)))
(if (= d 0)
( return-from ISPRIME t ))
(if (= (mod n d) 0)
( return-from ISPRIME nil ))
(ISPRIME n (- d 1)))
但是在运行我的代码时,我使用值5作为示例:
(ISPRIME 5)
Nil
5应该是素数。我怀疑所有内容都落入:(if(=(mod nd)0)语句,它不应该是.d应该继续减少直到达到0并返回true,但它不会。我似乎无法看看我的逻辑错误发生在哪里。
非常感谢任何和所有帮助!
答案 0 :(得分:4)
你的代码中有一个错误:函数应该停在1而不是0,因为任何数字都可以被1整除。只需改变函数就这样:
(defun ISPRIME (n &optional (d (- n 1)))
(if (= d 1) ; <- change from 0 to 1
( return-from ISPRIME t ))
(if (= (mod n d) 0)
( return-from ISPRIME nil ))
(ISPRIME n (- d 1)))
但请注意,您的函数效率不高,因为return-from
从函数的最后一次调用返回,而不是从“递归塔”返回,因此可以通过以这种方式消除它来重写函数,使用更紧凑的“条件”cond
,而不是if
,并将return-from
替换为结果:
(defun isprime (n &optional (d (- n 1)))
(cond ((= d 1) t)
((= (mod n d) 0) nil)
(t (isprime n (- d 1)))))
这仍然是递归的,但对于Common Lisp更为惯用。当然,可以在更有效的迭代版本中转换此函数,并应用更多efficient algorithm。但是请注意,智能编译器会在迭代中自动转换此函数,因为函数是tail recursive。
加
您还可以添加参数n
大于1的初始检查,例如:
(defun isprime (n &optional (d (- n 1)))
(cond ((<= n 1) nil)
((= d 1) t)
((= (mod n d) 0) nil)
(t (isprime n (- d 1)))))
答案 1 :(得分:2)
由于您计算的是布尔值,by
的实例可以替换为(if test T NIL)
,更一般地说,结果可能表示为单个布尔表达式。我倾向于发现它们更具可读性。以下是对接受的答案的一点修改作为例子:
test
为了完整性,并根据Will Ness的回答,这是一个LOOP版本:
(defun is-prime (n &optional (d (1- n)))
(or (= d 1)
(and (plusp d)
(plusp (mod n d))
(is-prime n (1- d)))))
等效的(defun is-prime (n)
(loop
for d = 2 then (+ d add)
for add = 1 then 2
thereis (> (* d d) n)
until (= (mod n d) 0)))
版本:
DO
答案 2 :(得分:2)
您不应该使用(尾部)递归,因为Common Lisp没有tail call optimization保证。请改为使用do
或loop
,甚至prog
使用go
。
在算法上, 总是 以 增加 顺序测试潜在的除数,从 2 <开始/ em>,当您超过 (sqrt n)
时停止:
(defun ISPRIME (n)
(prog ((d 2)) ; defines implicit block named NIL
LOOP
(if (> (* d d) n)
( return-from ISPRIME t )) ; (return T) also works
(if (= (mod n d) 0)
( return-from ISPRIME nil )) ; or just (return)
(if (= d 2)
(incf d 1)
(incf d 2))
(go LOOP)))
(return)
与(return nil)
相同,(return val)
与(return-from NIL val)
相同。由于prog
定义了一个名为NIL
的隐式块,更短,更通用,因此可以在那里使用对return
的调用。
这里有一个有趣的方法是使用一个可扩展的素数列表,它通过使用此isprime
函数过滤增加的数字来创建,在另一个{{{}}中用作除数。 1}}函数只能通过这些素数来测试它的参数,而不是所有的几率,从而实现另一种算法性能增益。素数列表应根据需要进行扩展。素数只会达到被测数的平方根,素数本身只需要通过最高素数的平方根的数字来测试(所以,被测数的第四个根)。