Lisp-素数

Lisp-素数,lisp,common-lisp,primes,primality-test,Lisp,Common Lisp,Primes,Primality Test,我正在努力学习lisp,我在素数方面有一些困难。我需要一个函数是prime,如果是prime,我必须返回t,如果不是,我必须返回nil (prime 41) => t (prime 35) => nil 到目前为止,我已经: (defun is-prime (n d) (if (= d 1) (print "t") (if (= (% n d) 0) (print "nil") (is-prime (n

我正在努力学习lisp,我在素数方面有一些困难。我需要一个函数
是prime
,如果是prime,我必须返回
t
,如果不是,我必须返回
nil

(prime 41) => t

(prime 35) => nil
到目前为止,我已经:

(defun is-prime (n d) 
  (if (= d 1) 
      (print "t") 
      (if (= (% n d) 0) 
          (print "nil") 
          (is-prime (n (- d 1) )))))

但是我有两个参数,我不知道如何只用一个。另外,它根本不起作用。有人能帮我吗?谢谢

你已经走到一半了

以下是我的英文解释:

您已经在lisp中编写了一个函数is prime(顺便说一句,“yes或no”这样的函数在lisp中通常被命名为whatever-p),它告诉您n相对于d是否是prime

你需要做的是遍历所有小于n的d,如果它不是它们中任何一个的相对素数,则返回nil,但如果在循环之后你没有返回nil,则返回t。这里您的朋友是函数“mod”,它告诉您当第一个参数除以第二个参数时是否有余数

比如:

(defun primep (n)
 (cond
  ((= 1    n)          nil)
   (t
   (loop
     :with root     = (isqrt n)
     :with divisors = (loop :for i :from 3 :to root :by 2 :collect i)
     :for d = (pop divisors)
     :if (zerop (mod n d))
     :do (return nil)
     :else :do (setf divisors (delete-if (lambda (x) (zerop (mod x d))) divisors))
     :while divisors
     :finally (return t)))))

另外,不要打印nil,只需返回nil。

您在这方面有一些错误:

(defun is-prime (n d) 
  (if (= d 1) 
      (print "t") 
      (if (= (% n d) 0) 
          (print "nil") 
首先,不要打印结果,只需返回即可。其次,没有
%
函数,它是
rem

真正的错误是如何进行递归调用。这里有一对额外的括号:

          (is-prime (n (- d 1) )))))
          ;         ^          ^
          ;        this      and this
在Lisp中,括号表示函数调用;但是您不打算用参数
(-d1)
调用
n
,它们都是
is prime
的参数。所以我们只需要去掉那些额外的括号

          (is-prime  n (- d 1)  ))))
那么它有什么作用呢?它倒计时:
d
(-d1)
<代码>1。当
(=d1)
时,它返回
t
。所以,有一种说法是

(defun is-prime (n &optional (d (- n 1))) 
  (or (= d 1)
      (and (/= (rem n d) 0)
           (is-prime  n (- d 1)))))
但这不是最有效的方法,也不是最安全的方法


首先,最好是向上计数,而不是向下计数,因为任何随机数的因子都比大的要小得多。然后,它让我们优化我们停在哪里——停在
sqrt
更有效,同样正确。

我从威尔·内斯的答案中得到启发,修改了函数。这是代码。Is检查1是否作为参数传递,并确保在这种情况下输出
nil

(defun is-prime (n &optional (d (- n 1))) 
  (if (/= n 1) (or (= d 1)
      (and (/= (rem n d) 0)
           (is-prime  n (- d 1)))) ()))

我仍在学习Common Lisp,因此如果这方面有问题,请告诉我。

我知道您在这里做什么,但我试图使其递归。如何使其递归并只保留一个参数n?可能,但这不是尾部递归的候选者,因此没有很好的理由使其递归(Lisp不仅仅是递归函数…)。让我看看我能做些什么…这看起来很光滑。你能评论一下递归和参数传递吗?函数是否在每次传递递减的第二个参数时调用自身?@ArtforLife“函数是否在每次传递递减的第二个参数时调用自身?”是。不是所有的时间,只要它需要这样做——也就是说,如果
d
不是
1
(当
t
返回时),并且
(rem n d)
不是
0
(当
NIL
返回时)。我明白了。使用参数1调用函数时,函数似乎会中断。它以零除法。@ArtforLife right.:)这就是我暗示的,用“不是……最安全的[调用此函数的方式]”:)知道了。那么一开始就应该进行一些检查了?此外,只需检查
d=isqrt(n)
及以下项即可进行优化。最好从2向上计数到sqrt(n)(包括),而不是从(n-1)向下计数到2。而且,CommonLisp不喜欢递归;你的意图是一个循环,所以最好把它写成一个循环。使用
循环
,或
执行
,或
程序
偶数。至于您的代码,您仍然没有处理
的情况。