一个简单求和公式∑i的LISP程序.我的代码是返回NIL,然后返回我想要的值,我能以某种方式不获得NIL吗



提问

(defun a-sum(n p)
(setq sum 0)

( loop for i from n to p  
do(setq sum (+ sum i))
)
(format t "~d" sum)       
)

我的代码适用于我的所有测试用例,但使用循环方法,我一直在值之前返回一个NIL。有什么办法阻止这种情况吗?或者可能是我在面对这样的问题时应该使用的一种化身方法?

以下是以可读方式格式化的代码,请参阅https://stackoverflow.com/help/formatting当提出问题并遵循格式化编程语言的传统方法时,您的问题是关于:

(defun a-sum (n p)
(setq sum 0)
(loop for i from n to p  
do (setq sum (+ sum i)))
(format t "~d" sum))

这里有一些问题,特别是:

  • 您在符号sum上调用SETQ,但作用域中没有用这样的名称声明的变量。使用let引入变量,例如:

    (let ((sum 0))
    ;; here you are allowed to use SETQ
    (setq sum 1))
    

    严格地说,您的代码不是Lisp的兼容程序,但它仍然有效:对SETQ的调用确实修改了sumsymbol-value,所以这就好像您使用了全局变量一样。这通常不是一个好主意,因为那时你的功能会产生不局限于身体的影响,还会改变环境。

  • 在函数体中,最后一个表达式是函数返回的值,因此这里返回的值是计算(format ...)的结果。在格式化为流的情况下(这里就是这种情况(,返回值总是NIL。这就是为什么你的结果是零。如果要返回sum,则需要将sum作为函数中的最后一个表达式。

  • 一般来说,一个函数应该做一件事,而不是把不同的操作混合在一起:要么计算一个和,要么打印它,但尽量不要同时做这两件事(调试时除外(。

  • loop结构足够强大,不需要使用中间sum、调用do (setq ...)等即可完成任务。阅读黑带的LOOP,您应该能够更简洁地重写它。

  • 连续数的和是一个众所周知的公式,它允许一个没有循环的解。

我一直拒绝回答,因为老师不应该问学生这样的问题(见下文(。

问题是写一个函数,计算i从n到p的和,其中n和p是整数,n和p>=0和p>=n(这个问题没有说明后一个要求,在答案中很容易放松它,但让我们假设它(。

好吧,在你写一些费力和徒劳的循环之前,先想一想。手写金额:

s = n + n+1 + ... + p
=   (n + n+1 + ... + p
+ p + p-1 + ... + n)/2
= (n+p + n+p + ... + n+p)/2

现在这个和中有(p-n+1(项,它们都是n+p。所以

s = (p - n + 1)*(n+p)/2

(defun a-sum (n p)
(/ (* (+ (- p n) 1)
(+ n p))
2))

这就是你这样做的原因:

> (time (a-sum/mindless 0 1000000000))
Evaluation took:
6.716 seconds of real time
6.716005 seconds of total run time (6.713082 user, 0.002923 system)
100.00% CPU
0 bytes consed

500000000500000000
> (time (a-sum 0 1000000000))
Evaluation took:
0.000 seconds of real time
0.000003 seconds of total run time (0.000002 user, 0.000001 system)
100.00% CPU
0 bytes consed

500000000500000000

所以事情是这样的:如果你是讲师,并且你正在阅读这篇文章(我相信你是,因为我会的(不要问那些有众所周知的闭式解决方案的问题,并期望学生写出可怕的暴力解决方案,因为这样做是教人们成为糟糕的程序员而你不应该这样做。

最新更新