2014年11月7日金曜日

[SICP] 問題 1.32 : accumulate

a. sumと(問題1.31の)productは, 一般的なアキュムレーションの関数:
(accumulate combiner null-value term a next b)
を使い, 項の集りを組み合せるaccumulateという更に一般的なものの特殊な場合であることを示せ.
accumulateは引数としてsumや productと同様, 項と範囲指定と, 先行する項のアキュムレーションと現在の項をどう組み合せるかを指定する(二引数の)combiner手続き, 項がなくなった時に使う値を指定するnull-valueをとる. accumulateを書き, sumやproductがaccumulateの単なる呼出しで定義出来ることを示せ.

b. 上のaccumulateが再帰的プロセスを生成するなら, 反復的プロセスを生成するものを書け. 反復的プロセスを生成するなら, 再帰的プロセスを生成するものを書け.
手続きsumとproductを比較すると, 「+」と「*」がcombiner, 「0」と「1」がnull-valueに対応します. 手続きを定義すると次のようになります.
(require (lib "racket/trace.ss"))

(define (square x) (* x x))

(define (cube x) (* x x x))

;; 再帰的プロセスを生成する.
(define (accumulate-r combiner null-value term a next b)
  (if (> a b)
      null-value
      (combiner (term a)
                (accumulate-r combiner null-value term (next a) next b))))

;; 反復的プロセスを生成する.
(define (accumulate-i combiner null-value term a next b)
  (define (iter a result)
    (if (> a b)
        result
        (iter (next a) (combiner (term a) result))))
  (iter a null-value))

;; 総和の定義
(define (sum term a next b)
  (accumulate-r + 0 term a next b))

;; 定積分を求める.
(define (integral f a b dx)
  (define (add-dx x) (+ x dx))
  (* (sum f (+ a (/ dx 2.0)) add-dx b)
     dx))

;; 指定した範囲の関数値の積を求める.
(define (product term a next b)
  (accumulate-i * 1 term a next b))

;; 円周率を求める. 
(define (my-pi n)
  (define (term x) 
    (/ (* x (+ x 2)) (square (+ x 1))))
  (define (next x)
    (+ x 2))
  (* 4.0 (product term 2 next n)))
実行してみます.
ようこそ DrRacket, バージョン 6.1 [3m].
言語: Pretty Big; memory limit: 2048 MB.
> (integral cube 0 1 0.01)
0.24998750000000042
> (integral cube 0 1 0.001)
0.249999875000001
> (my-pi 10000)
3.141749705738071
> (my-pi 100000)
3.141608361278168
> 
これまでの問題と同様に計算できています.

0 件のコメント:

コメントを投稿