理系学生日記

おまえはいつまで学生気分なのか

高階関数

なんか数学的な問題はぶっ飛ばして,高階関数に入りました.関数型言語っぽくなってなんかちょっとうれしい感じ.学部でMLやって以来の,久しぶりのわくわく感です!

問題1.29

simpson法で定積分を行うプログラムをつくってみました.

(define (sum term a next b)
  (if (> a b)
      0
      (+ (term a)
         (sum term (next a) next b))))

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

(define (simpson f a b n)
  (define (calc-h a b n)
    (/ (- b a) n))
  (define h (calc-h a b n))
  (define (next val) (+ val (* 2 h)))
  (* (/ h 3)
     (+ (f a)
        (f (+ a (* n h)))
        (* 4 (sum f (+ a h) next (+ a (* (- n 1) h))))
        (* 2 (sum f (+ a (* 2 h)) next (+ a (* (- n 2) h)))))))

(print (simpson square 0 1 100))
(print (simpson cube 0 1 100))

積分区間を[0,1]として,x**2,x**3を計算してみましたが,なんか出力が1/3,1/4とかなっててびっくりしました.というのも,有理数が出力されたので.どうなってんだこれ.なんでなんで?


と思ったら,整数の割り算してた.2 -> 2.0とかそういうことをやらないといけないのね.最近ずっとperlだったから忘れてました.

問題1.30

問題1.29の問題ででてきてるsumが線形再帰で効率が悪いとかで,反復的に計算できるsumを作ります.

(define (sum term a next b)
  (define (iter a result)
    (if (> a b)
        result
        (iter (next a) (+ result (term a)))))
  (iter a 0))

(define (inc x) (+ x 1))
(define (self x) x)

(print (sum self 0 inc 10))

1から10を足してみたら55になったので,たぶん合ってるんじゃないかと.ブロック構造を使うと,外側でbindされた文字が使えるってところを忘れてて,けっこう長い間はまったりしまいました.そこさえ思い出せればなんとかなったみたいです.しかし,関数型のキホンって,反復構造なんだろうか.線形再帰を反復に書き直せって問題が多い気がします.

問題1.30

sum (Σ)じゃなくてproduct(Π)を作るそうです.sumを2箇所だけ変えるとできる.

(define (product term a next b)
  (define (iter a result)
    (if (> a b)
        result
        (iter (next a) (* result (term a)))))
  (iter a 1))

で、このproductをつかうと,階乗はこう書ける.

(define (inc x) (+ x 1))
(define (self x) x)

(define (factorial n)
  (product self 1 inc n))

ついでに,π/4をWallisの公式で計算するのはこう.

(define (square x) (* x x))
(define (plus-2 x) (+ x 2))

(define (right-angle max)
  (/ (* 2.0 (product square 4 plus-2 max))
     (* (+ max 1) (product square 3.0 plus-2 (- max 1)))))

ただ,あんまり計算を多くすると#とかでてくる.いけてない.出力も0.781519725053853
だったので,π/4とかなり違う.wallisの公式の限界ってやつですか?もしかして間違えてる?