Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/ant/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Lisp中,如何将1000以下所有可被3或5整除的数字相加?_Lisp_Common Lisp_Sbcl - Fatal编程技术网

在Lisp中,如何将1000以下所有可被3或5整除的数字相加?

在Lisp中,如何将1000以下所有可被3或5整除的数字相加?,lisp,common-lisp,sbcl,Lisp,Common Lisp,Sbcl,我昨天开始用CommonLisp编程。现在我想。我想到了: (loop for n from 1 to 1000 when (or (eq (mod n 5) 0) (eq (mod n 3) 0)) (sum n))) 我知道循环部分工作(loop for n from 1 to 1000 sum n)对前1000个数字求和。我知道((eq(mod n 5)0)(mod n 3)0))部件工作正常。我知道(或者(eq(mod n5)0)(eq(

我昨天开始用CommonLisp编程。现在我想。我想到了:

(loop for n from 1 to 1000 when 
     (or 
      (eq (mod n 5) 0)
      (eq (mod n 3) 0))
     (sum n)))
我知道循环部分工作(
loop for n from 1 to 1000 sum n)
对前1000个数字求和。我知道
((eq(mod n 5)0)(mod n 3)0))
部件工作正常。我知道
(或者(eq(mod n5)0)(eq(mod n3)0))
是有效的。因此,对我来说,它看起来像一个健壮的程序,但当我运行它时,我得到了错误:

1=(SUM N)在WHEN当前循环上下文之后找到where关键字expected get循环子句:WHEN(或(EQ(MOD 1000 5)0) (等式(MOD 1000 3)0) 1#. [SB-INT类型的条件:简单程序错误]

我怀疑or语句后面的
(sum n)
有问题。但我不知道这是为什么,也不知道如何解决。有人能帮我把我的第一个Lisp程序运行起来吗?

sum n
,而不是
(sum n)
不要把
sum n
放在括号里。
循环
宏是它自己的领域特定语言,具有自己的语法。有了它,您将
(循环…sum n)
。本产品中的HyperSpec条目中给出了语法:

numeric-accumulation::= {count | counting | sum | summing | } 
                         maximize | maximizing | minimize | minimizing {form | it} 
                        [into simple-var] [type-spec] 
如果听起来更好的话,您还可以编写
(循环…求和n)
。这可能更像是一个自然的英语句子

=
eql
zerop
,但不是
eq
在HyperSpec中查找函数、宏等是一种很好的做法。正如雷纳·乔斯维格所指出的,你不应该用
eq
来比较数字。为什么?让我们在HyperSpec中查找它。这些例子包括:

(eq 3 3)
=>  true
OR=>  false
 (eq 3 3.0) =>  false
 (eq 3.0 3.0)
=>  true
OR=>  false
 (eq #c(3 -4) #c(3 -4))
=>  true
OR=>  false
注释部分说(增加强调):

打印时显示相同的对象不一定相等 彼此打印相同内容的符号通常彼此相等 因为使用了实习生功能但是,带有 相同的值不必为eq,两个相似的列表通常不需要 一模一样

允许实现“复制”字符和 任何时候都可以使用数字。其效果是Common Lisp不能保证 即使eq的两个参数“相同”,如果 那东西是一个字符或数字。

对于数字,你需要一些其他的东西
=
是一个很好的通用数字比较,尽管它在这里做的工作比您需要的要多,因为它可以比较不同类型的数字。例如,
(=5.0)
为真。因为您只关心
0
,所以可以使用
zerop
,但这仍然会比您需要做更多的工作,因为它还会检查其他数字类型。例如,
(zerop#c(0.0 0.0))
是真的。在这种情况下,由于
(mod n…
将给您一个整数,因此您可以使用
eql

eql的值对于以下两个对象(x和y)为真 案例:

  • 如果x和y是等式
  • 如果x和y都是相同类型和相同值的数字。
  • 如果它们都是表示相同字符的字符
  • 因此,您可以使用
    (或(eql(mod n 3)0)(eql(mod n 5)0))

    其他方法 现在,你的问题是关于循环语法的一个特殊部分,关于等式运算符有一些要点需要说明。然而,由于其他一些答案已经研究了其他方法来实现这一点,我认为值得指出的是,有更有效的方法来实现这一点。首先,让我们看一种方法,将给定极限下某个数字的所有倍数相加。例如,对于数字3和包含限制26,我们有总和


    =3+6+9+12+15+18+21+24
    =(3+24)+(6+21)+(9+18)+(12+15)
    =27+27+27+27

    一般来说,如果你试着用几个不同的数字,你可以算出,对于一个包含的极限l和一个数字n,你将把数对相加,如果有一个奇数的n的倍数小于l,你可以选择半对。我不打算计算出整个推导过程,但你可以用

    (defun sum-of-multiples-below-inclusive (limit divisor)
      (multiple-value-bind (quotient remainder) 
          (floor limit divisor)
        (let ((pair (+ (- limit remainder) divisor)))
          (multiple-value-bind (npairs half-pair)
              (floor quotient 2)
            (+ (* npairs pair)
               (if (oddp half-pair)
                   (floor pair 2)
                   0))))))
    
    然后,要找出小于给定数字的倍数之和,您可以从“限制”中减去一:

    (defun sum-of-multiples-below (limit divisor)
      (sum-of-multiples-below (1- limit) divisor))
    
    然后,为了扩展到有多个除数的情况,需要将这些数相加,然后减去两次计数的数。例如,在您的情况下:

    (+ (sum-of-multiples-below 1000 3)
       (sum-of-multiples-below 1000 5)
       (- (sum-of-multiples-below 1000 15)))
    ;=> 233168
    
    
    (loop for i from 1 below 1000 
       when (or (eql 0 (mod i 3))
                (eql 0 (mod i 5)))
       sum i)
    ;=> 233168
    
    现在,天真地使用
    time
    可能会导致误导性结果,但SBCL会在对表单求值之前编译表单,所以这并不可怕。这是一个非常非常小的微型基准测试,但看看每种形式中使用的周期数:

    (time (+ (sum-of-multiples-below 1000 3)
             (sum-of-multiples-below 1000 5)
             (- (sum-of-multiples-below 1000 15))))
    Evaluation took:
      0.000 seconds of real time
      0.000000 seconds of total run time (0.000000 user, 0.000000 system)
      100.00% CPU
      11,327 processor cycles
      0 bytes consed
    
    使用封闭形式要快得多。如果我们使用更高的限值,则差异更为明显。让我们看看100000:

    (time (+ (sum-of-multiples-below 100000 3)
             (sum-of-multiples-below 100000 5)
             (- (sum-of-multiples-below 100000 15))))
    Evaluation took:
      0.000 seconds of real time
      0.000000 seconds of total run time (0.000000 user, 0.000000 system)
      100.00% CPU
      13,378 processor cycles
      0 bytes consed
    
    对于10000000人来说,数字甚至更令人震惊:

    (time (+ (sum-of-multiples-below 10000000 3)
             (sum-of-multiples-below 10000000 5)
             (- (sum-of-multiples-below 10000000 15))))
    Evaluation took:
      0.000 seconds of real time
      0.000000 seconds of total run time (0.000000 user, 0.000000 system)
      100.00% CPU
      13,797 processor cycles
      0 bytes consed
    
    其中一些项目Euler问题非常有趣。他们中的一些人有一些非常简单的天真解决方案,这些解决方案只适用于小的输入,但根本不能很好地扩展

    sum n
    ,而不是
    (sum n)
    不要把
    sum n
    放在括号里。
    循环
    宏是它自己的领域特定语言,具有自己的语法。有了它,您将
    (循环…sum n)
    。本产品中的HyperSpec条目中给出了语法:

    numeric-accumulation::= {count | counting | sum | summing | } 
                             maximize | maximizing | minimize | minimizing {form | it} 
                            [into simple-var] [type-spec] 
    
    如果听起来更好的话,您还可以编写
    (循环…求和n)
    。这可能更像是一个自然的英语句子

    =
    eql
    zerop
    ,但不是
    eq
    在HyperSpec中查找函数、宏等是一种很好的做法。正如雷纳·乔斯维格所指出的,你不应该用
    eq
    来比较数字。为什么?让我们在HyperSpec中查找它。例子
    (time (+ (sum-of-multiples-below 10000000 3)
             (sum-of-multiples-below 10000000 5)
             (- (sum-of-multiples-below 10000000 15))))
    Evaluation took:
      0.000 seconds of real time
      0.000000 seconds of total run time (0.000000 user, 0.000000 system)
      100.00% CPU
      13,797 processor cycles
      0 bytes consed
    
    (time (loop for i from 1 below 10000000
             when (or (eql 0 (mod i 3))
                      (eql 0 (mod i 5)))
             sum i))
    
    Evaluation took:
      0.712 seconds of real time
      0.712044 seconds of total run time (0.712044 user, 0.000000 system)
      100.00% CPU
      1,916,513,379 processor cycles
      0 bytes consed
    
    (loop for n from 1 below 1000
          when (or (zerop (mod n 3))
                   (zerop (mod n 5)))
          sum n))
    
    (defun sum-to-thousand (count result)
           (cond ((> count 1000) result)
             ((= (mod count 3) 0) (sum-to-thousand (+ count 1) (+ count result)))
             ((= (mod count 5) 0) (sum-to-thousand (+ count 1) (+ count result)))
             (t (sum-to-thousand (+ count 1) result))))
    
    CL-USER> (defun my-sum (&key (from 1) to dividers (sum 0))
               (if (>= from to)
                   sum
                   (my-sum :from (1+ from)
                           :to to
                           :dividers dividers
                           :sum (if (some (lambda (x) (zerop (mod from x))) dividers)
                                    (+ sum from)
                                    sum))))
    MY-SUM
    CL-USER> (my-sum :to 1000 :dividers '(3 5))
    233168