0

スキームで1000未満の3と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)))
4

6 に答える 6

1

cond問題の 1 つは、句を囲む括弧のペアがコードにないことです。この行(cond (> a 1000) (sum)では、条件はただの>while aであり、 true の1000場合に評価されるフォームとして解釈され>ます (これはそうです)。したがって、結果として 1000 が返されます。

他の 2 つの問題 (最初の問題でマスクされています) は、ctr が 7 に達したときに 0 に初期化しているのに、次の値、つまり 1 に設定する必要があり、結果に 1000 が含まれていることです。

関数の修正版は

(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)))  
于 2012-12-21T19:09:20.283 に答える
1

sumaccumulator( parameter) とパラメーターを使用して、target合計をいつ停止するかをテストすることにより、命令型スタイルのソリューションを機能的なスキームに簡単に移植できます。

(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))
于 2012-12-21T16:43:46.253 に答える
1

これは私の(Racket固有の)ソリューションであり、多くの(または、さらに言えば、すべての)呼び出しを伴わず、完全に一般的です( OPが持つリストmoduloを作成する必要がないように):(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
于 2012-12-21T17:00:36.863 に答える
1

Racket を使用している場合は、ループ構造を使用して、要求を実行する非常にコンパクトな方法があります。

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

=> 233168
于 2012-12-21T17:01:43.660 に答える
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 つインクリメントする場合に実行する操作の平均で半分の操作が実行され、チェックする条件の場合は 1 つ少なくなります。

また、モジュロ (おそらく変装した除算であるため) は、合計よりもコストがかかります。

編集: 私は、Scheme のさまざまな方言のモジュラー システムのプロではありません。ここでの SRFI-1 拡張は、循環リストの作成を容易にするためにのみ必要です。Common Lisp(#0=(3 2 1 3 1 2 3) . #0#)に相当するものを見つけることができませんでしたが、おそらく、より知識のある人がこれを修正するでしょう。

于 2012-12-21T17:47:41.033 に答える
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))
于 2012-12-28T14:22:45.343 に答える