计算3&的倍数之和5低于1000

时间:2012-12-21 16:25:00

标签: lisp scheme

我编写了以下程序来计算3&的所有倍数的总和。方案中低于1000的5。但是,它给我一个不正确的输出。 任何帮助将不胜感激。

(define  (multiples)
   (define  (calc  a sum ctr cir)
      (cond (> a 1000) (sum)
            (= ctr 7) (calc (+ a (list-ref cir 0)) (+ sum a) 0 (list 3 2 1 3 1 2 3))
             (else (calc (+ a (list-ref cir ctr)) (+ sum a) (+ 1 ctr) (list 3 2 1 3 1 2 3)))))
    (calc 0 0 0 (list 3 2 1 3 1 2 3)))

6 个答案:

答案 0 :(得分:1)

您可以通过使用累加器(sum参数)和target参数来测试何时停止求和,将命令式样式解决方案移植到函数Scheme:

(define (multiples)
  (define (multiples-iter num sum target)
    (if (> num target)
      sum
      (multiples-iter (+ 1 num)
                      (if (or (zero? (mod num 3)) (zero? (mod num 5)))
                        (+ sum num)
                        sum)
                      target)))
  (multiples-iter 0 0 1000))

答案 1 :(得分:1)

这是我的(特定于球拍)解决方案,它不涉及很多(或者,对于任何)modulo次调用,并且是完全通用的(因此您不需要构建OP列出的(3 2 1 3 1 2 3)列表:

(define (sum-of-multiples a b limit)
  (define (sum-of-multiple x)
    (for/fold ((sum 0))
              ((i (in-range 0 limit x)))
      (+ sum i)))
  (- (+ (sum-of-multiple a) (sum-of-multiple b))
     (sum-of-multiple (lcm a b))))

试运行:

> (sum-of-multiples 3 5 1000)
233168

答案 2 :(得分:1)

如果您正在使用Racket,那么使用循环结构可以非常紧凑地执行您的要求:

(for/fold ([sum 0])
  ([i (in-range 1 1000)]
   #:when (or (zero? (modulo i 3)) (zero? (modulo i 5))))
  (+ sum i))

=> 233168

答案 3 :(得分:1)

一个问题是您的代码缺少围绕cond子句的一对括号。 在(cond (> a 1000) (sum)行中,条件仅为>,而a1000被解释为在>为真(即它)时要评估的表单,因此将返回1000作为结果。

另外两个问题(由第一个掩盖)是你在达到7时将ctr初始化为0,而它应该被设置为下一个值,即1,并且你在结果中包含1000。 / p>

您的功能的更正版本是

(define  (multiples)
   (define  (calc  a sum ctr cir)
      (cond ((>= a 1000) sum)
            ((= ctr 7) (calc (+ a (list-ref cir 0)) (+ sum a) 1 (list 3 2 1 3 1 2 3)))
             (else (calc (+ a (list-ref cir ctr)) (+ sum a) (+ 1 ctr) (list 3 2 1 3 1 2 3)))))
    (calc 0 0 0 (list 3 2 1 3 1 2 3)))

同样的算法也可以定义为非递归函数,如下所示:

(define (multiples)                                                             
  (do ((cir (list 3 2 1 3 1 2 3))                                               
       (ctr 0 (+ ctr 1))                                                        
       (a 0 (+ a (list-ref cir (modulo ctr 7))))                                
       (sum 0 (+ sum a)))                                                       
      ((>= a 1000) sum)))  

答案 4 :(得分:0)

(require-extension (srfi 1))
(define (sum-mod-3-5 upto)
  (define (%sum-mod-3-5 so-far generator-position steps)
    (let ((next (car generator-position)))
      (if (> (+ steps next) upto)
          so-far
          (%sum-mod-3-5 (+ so-far steps)
                        (cdr generator-position)
                        (+ steps next)))))
  (%sum-mod-3-5 0 (circular-list 3 2 1 3 1 2 3) 0)) ; 233168

对于这个特定的任务,如果将计数器递增1,它将平均执行一半的操作,如果要检查的条件也减少一个。

另外,模数(可能是伪装的分割)比求和更贵。

编辑:我不是Scheme的不同方言的模块化系统的专业人士。此处的SRFI-1扩展仅需要更容易创建循环列表。我找不到Common Lisp (#0=(3 2 1 3 1 2 3) . #0#)的类似物,但也许更有知识的人会纠正这个。

答案 5 :(得分:0)

如果你绝对想要使用“重复模式”方法,你可以这样做。

这在间隔列表中使用递归,而不是依赖于list-ref和显式索引。

(define (mults limit)
  (define steps '(3 2 1 3 1 2 3))
  (define (mults-help a sum ls)
    (cond ((>= a limit) sum)
          ((null? ls) (mults-help a sum steps))
          (else (mults-help (+ a (car ls)) 
                            (+ a sum)  
                            (cdr ls)))))
  (mults-help 0 0 steps))