Exercise1.1~1.19

Exercise1.1

gosh> 10
10
gosh> (+ 5 4 3)
12
gosh> (- 9 1)
8
gosh> (/ 6 2)
3
gosh> (+ (* 2 4) (- 4 6))
6
gosh> (define a 3)
a
gosh> (define b (+ a 1))
b
gosh> (+ a b (* a b))
19
gosh> (= a b)
#f
gosh> (if (and (> b a) (< b (* a b)))
..... b
..... a)
4
gosh> (cond ((= a 4) 6)
.....       ((= b 4) (+ 6 7 a))
.....       (else 25))
16
gosh> (+ 2 (if (> b a) b a))
6
gosh> (* (cond ((> a b) a)
.....          ((< a b) b)
.....          (else -1))
.....    (+ a 1))
16
by iwk

Exercise1.2

gosh> (/ (+ 5 4 (- 2 (- 3 (+ 6 (/ 4 5))))) 
.....    (* 3 (- 6 2) (- 2 7)))
-0.24666666666666667

by iwk

Exercise1.3

(define (func a b c)
  (if (>= a b)
      (+ (* a a) 
	 (if (>= b c)
	     (* b b)
	     (* c c)))
      (+ (* b b)
	 (if (>= a c)
	     (* a a)
	     (* c c)))))
実行例
SC> (func 1 2 3)
13
SC> (func 2 2 3)
13
SC> (func 2 2 2)
8
by Alyssa

別解(再帰呼び出しによる解答)
(define (sum-square-largest x y z)
  (cond ((and (< x y) (< x z))
         (+ (* y y) (* z z)))
        (else (sum-square-largest y z x))))

Exercise1.4

(define (a-plus-abs-b a b)
  ((if (> b 0) + -) a b))

;; b>0ならば,(+ a b)が評価され,そうでないなら(- a b)が評価される.
;; つまり,この手続きはaと,bの絶対値を足した値を返す.
;; このように基本演算子を,あたかもデータであるかのように返すことが可能なのである.
実行例
SC> (a-plus-abs-b 1 -2)
3
SC> (a-plus-abs-b 1 2)
3
by Alyssa


Exercise1.5

(define (p) (p))

(define (test x y)
  (if (= x 0)
      0
      y))

;; testは,自らが定義した手続きであるので,作用的順序(applicative order)の場合,test手続きに引数x,yを作用(apply)させる前に,引数x,yを評価する.
;; ゆえに,(test 0 (p))の評価において,(p)はそれ自身(p)と定義されているので,引数(p)の評価が終わらず,無限ループとなる.
;; 一方,正規順序(normal order)の場合,引数の評価はその引数の値が必要となるまで遅延(delay)される.
;; 今の場合,手続きtestの本体はif文であり,まず述語式{(= x 0)}の評価に入り,今xは0であるので,(= 0 0)となりこれは真であるので,
;; 代替部{y}を評価することなく,そのまま帰結部{0}を返す.よって無限ループには陥らない.

;; (参考)
;; この様に書くと,正規順序の方が優れているように見えますが,計算効率などを考え普通の解釈系は作用的順序です.
;; 正規順序の解釈系の実装については,4.2で詳しくやります.
by Alyssa

Exercise1.6

(define (new-if predicate then-clause else-clause)
  (cond (predicate then-clause)
	(else else-clause)))

(define (sqrt-iter guess x)
  (new-if (good-enough? guess x)
	   guess
	   (sqrt-iter (improve guess x)
		      x)))

;; new-ifはあくまで手続きであるので,引数を全て評価してからnew-if本体に作用させる.
;; ゆえに,引数else-clause(ifでいう代替部)にあたる(sqrt-iter ..)の部分の評価でさらにその中のsqrt-iterを評価し,と無限ループに陥る.

;; (参考)
;; なぜ普通のifではこの様な無限ループに陥らないかというと,ifは手続きではなくあくまで特殊形式であり,
;; まず述語部を評価して,その真偽に応じて,帰結部か代替部を初めて評価するので,(good-enough? ..)の部分が真になった時点で,代替部の(sqrt-iter ..)は評価されないのです.
;; ですので例えば,(if (= 0 0) 1 (/ 1 0))なども(一応)エラーが出ずに通ります.
by Alyssa

Exercise1.7

(define (average x y)
  (/ (+ x y) 2))
(define (improve guess x)
  (average guess (/ x guess)))

(define (sqrt-iter guess next-guess x)
  (if (good-enough? guess next-guess)
      next-guess
      (sqrt-iter next-guess (improve next-guess x) x)))

(define (good-enough? guess next-guess)
  (< (abs (/ (- next-guess guess) next-guess)) 0.001))

(define (sqrt x)
  (sqrt-iter 1.0 (improve 1.0 x) x))

;; 変更する前のsqrtでは,小さい値の場合誤差が酷く,大きい値の場合永久に結果が出ない場合があります.
;; この原因は,good-enough?が求めるべき値との絶対的な誤差で判断しているからです.
;; ですので,重要な変更点はgood-enough?です.
;; 推測値が十分に変化しなくなった相対的な誤差で判断させます.
;; こちらは有効数字的な考え方ですので,酷く結果がずれることも,永久に値が出ないこともありません.
実行例
;; 改良前(本文中に出てくるsqrt)
SC> (sqrt .0002)
0.0333528160928043
;; 誤差が酷い
SC> (sqrt 20000000000000000000000000000000000)
;; 停止しない

;; 改良後(上のソースのsqrt)
SC> (sqrt .0002)
0.0141421356237384
SC> (sqrt 20000000000000000000000000000000000)
1.41421379705111e+17
;; ともにちゃんとした値がでる
by Alyssa


Exercise1.8

(define (curt-iter guess x)
  (if (good-enough? guess x)
      guess
      (curt-iter (improve guess x) x)))

(define (improve guess x)
  (/ (+ (/ x guess guess) (* 2 guess)) 3))

(define (good-enough? guess x)
  (< (abs (- (cube guess) x)) .001))

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

(define (curt x) (curt-iter 1.0 x)
実行例
SC> (curt 1.0)
1.0
SC> (curt 2.0)
1.25993349344998
SC> (curt 8.0)
2.0000049116755

;; ただし,これもEx1.7と同じ理由で,小さい値や大きい値には対応できません.
by Alyssa


Exercise1.9

(define (inc a) (+ a 1))
(define (dec a) (- a 1))

(define (+_1 a b)
  (if (= a 0)
      b
      (inc (+_1 (dec a) b))))

(define (+_2 a b)
  (if (= a 0)
      b
      (+_2 (dec a) (inc b))))

;; (注:2つの+を区別するために問題文とは名前を変えています.)
;; 以下プロセス

(+_1 4 5)
(inc (+_1 (dec 4) 5))
(inc (+_1 3 5))
(inc (inc (+_1 (dec 3) 5)))
(inc (inc (+_1 2 5)))
(inc (inc (inc (+_1 (dec 2) 5))))
(inc (inc (inc (+_1 1 5))))
(inc (inc (inc (inc (+_1 (dec 1) 5)))))
(inc (inc (inc (inc (+_1 0 5)))))
(inc (inc (inc (inc 5))))
(inc (inc (inc 6)))
(inc (inc 7))
(inc 8)
9
これは再帰的

(+_2 4 5)
(+_2 (dec 4) (inc 5))
(+_2 3 6)
(+_2 (dec 3) (inc 6))
(+_2 2 7)
(+_2 (dec 2) (inc 7))
(+_2 1 8)
(+_2 (dec 1) (inc 8))
(+_2 0 9)
9
これは反復的
by Alyssa


Exercise1.10

(define (A x y)
  (cond ((= y 0) 0)
 	 ((= x 0) (* 2 y))
	 ((= y 1) 2)
	 (else (A (- x 1) (A x (- y 1))))))

(define (f n) (A 0 n))
(define (g n) (A 1 n))
(define (h n) (A 2 n))
実行例
SC> (A 1 10)
1024
SC> (A 2 4)
65536
SC> (A 3 3)
65536

また,f(n)=2*n,f(0)=0,f(1)=2より,
f(n) = 2n
同様に,g(n)=2*g(n-1),g(1)=2より,
g(n) = 2^n (これはn=0の時も成り立つ)
最後に,h(n) = 2^h(n-1),h(1)=2より,
h(n) = (n≠0) 2^(2^(2^...^(2^2))...)) (2がn個表れる)
         (n=0) 0
by Alyssa

Exercise1.11

;; 再帰
(define (f-r n)
  (if (<= n 3) 
      n
      (+ (f-r (- n 1)) (* 2 (f-r (- n 2))) (* 3 (f-r (- n 3))))))

;; 反復
(define (f-i n)
  (define (iter a b c count)
    (cond ((<= n 2) n)
	  ((= count n) a)
	  (else (iter (+ a (* 2 b) (* 3 c)) a b (+ count 1)))))
  (iter 3 2 1 3))
実行例
SC> (f-r 2)
2
SC> (f-r 15)
124905
SC> (f-i 2)
2
SC> (f-i 15)
124905
by Alyssa

Exercise1.12

(define (pascal n k)
  (cond ((= k 0) 1)
      	 ((= k n) 1)
      	 (else (+ (pascal (- n 1) (- k 1)) (pascal (- n 1) k)))))

;; ただし上のn,kは,上からn(n>=0)番目の段の左からk(k>=0)個目の要素としています.
実行例
SC> (pascal 5 2)
10
SC> (pascal 10 8)
45
by Alyssa

Exercise1.13

schemeとは直接関係ありませんし書くのも面倒なのでアイディアだけ.

まず,言われた通り,帰納法なりなんなりでFib(n)=(φ^n - ψ^n)/√5を示し,
ここでn>=0において,0<ψ<1より,(ψ^n)/√5 < 1/√5 < 1/√4 = 0.5であるので,
これらよりFib(n)は(φ^n)/√5にもっとも近い整数といえます.
by Alyssa

Exercise1.14

(amount , kinds-of-coins)
(11 , 5) - ( -39 , 5) <- 0
    |
(11 , 4) - ( -14 , 4) <- 0
    |
(11 , 3) - ( 1 , 3) - ( -9 , 3) <- 0
    |          |
    |      ( 1 , 2) - ( -4 , 2) <- 0
    |          |
    |      ( 1 , 1) - ( 0 , 1 ) <- 1
    |          |
    |      ( 1 , 0) <- 0
    |
(11 , 2) - ( 6 , 2) - ( 1 , 2 ) - ( -4 , 2) <- 0
    |          |          |
    |          |      ( 1 , 1 ) - ( 0 , 1 ) <- 1
    |          |          |
    |          |      ( 1 , 0 ) <- 0
    |          |
    |      ( 6 , 1) - ( 5 , 1 ) - ( 4 , 1 ) - ( 3 , 1) - ( 2 , 1) - ( 1 , 1) - ( 0 , 1) <- 1
    |          |          |           |           |          |          |
    |          |          |           |           |          |      ( 1 , 0) <- 0
    |          |          |           |           |          |
    |          |          |           |           |      ( 2 , 0) <- 0
    |          |          |           |           |
    |          |          |           |       ( 3 , 0) <- 0
    |          |          |           |
    |          |          |       ( 4 , 0 ) <- 0
    |          |          |
    |          |      ( 5 , 0 ) <- 0
    |          |
    |      ( 6 , 0) <- 0
    |
(11 , 1) - (10 , 1) - ( 9 , 1 ) - ( 8 , 1 ) - ( 7 , 1) - ( 6 , 1) - ........ - ( 1 , 1) - ( 0 , 1) <- 1
    |          |          |           |           |          |                     |
    |          |          |           |           |          |                 ( 1 , 0) <- 0
    |          |          |           |           |      ( 6 , 0) <- 0
    |          |          |           |           |
    |          |          |           |       ( 7 , 0) <- 0
    |          |          |           |
    |          |          |       ( 8 , 0) <- 0
    |          |          |
    |          |      ( 9 , 0 ) <- 0
    |          |
    |      (10 , 0) <- 0
    |
(11 , 0) <- 0

増加の程度
スペース Θ(n) , ステップ数 Θ(a^n)
by iriya

Exercise1.15

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

(define (p x) (- (* 3 x) (* 4 (cube x))))

(define (sine angle)
  (if (not (> (abs angle) 0.1))
      angle
      (p (sine (/ angle 3.0)))))

;; (a)
;; angleの絶対値が0.1より大きい時にpは呼ばれるので,
;; angel:12.15 > 4.05 > 1.35 > 0.45 > 0.15 > 0.05となることから
;; pは5回呼び出される.

;; (b)
;; 手続きpは,xにたいしてステップもスペースももちろんθ(1)である.
;; よって手続きsineは,pを呼び出す数に比例してステップが増え,スペースも同様である.
;; 今,ある(0.1より大きい)angleについて,その3倍の3*angleの(sine (* 3 angle))を考えると,
;; これは(p (sine angle))を呼び出すので,(sine angle)に対して一つステップもスペースも増える.
;; つまり,sineのオーダーをf(n)と表すなら,f(3n) = f(n) + 1が成り立つのである.
;; これを満たすfは,log_{3}(n)である.
;; よって,sineはステップもスペースもθ(log_{3}(n))である.
;; (補足)
;; ようは,angleが1/3ずつになっていくのでθ(log_{3}(n))なのです.
by Alyssa

Exercise1.16

;; http://ja.wikipedia.org/wiki/%E5%86%AA%E4%B9%97
;; 効率的演算法 の最初の方法から着想

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

(define (even? n)
  (= (remainder n 2) 0))

(define (fast-expt-iter a b n)
  (cond ((= n 0) a)
        ((even? n) (fast-expt-iter a (square b) (/ n 2)))
        (else (fast-expt-iter (* a b) b (- n 1)))))

(define (fast-expt b n)
  (fast-expt-iter 1 b n))
by kacchi

Exercise1.17

(define (halve x) (/ x 2))
(define (double x) (* x 2))
(define (even? n)
  (= (remainder n 2) 0))

(define (x a b)
  (cond ((= b 0) 0)
        ((even? b) (double (x a (halve b))))
        (else (+ a (x a (- b 1))))))

gosh> (x 123 4567890987654321)
561850591481481483
gosh> (* 123 4567890987654321)
561850591481481483
by kacchi

Exercise1.18

Exercise1.16 と同じ形なので、そのままあてはめた。

(define (double x) (+ x x))

(define (x a b)
  (x-iter 0 a b))

(define (x-iter product a b)
  (cond ((= b 0) product)
        ((even? b) (x-iter product (double a) (/ b 2)))
        (else (x-iter (+ a product) a (- b 1)))))
by kacchi

Exercise1.19

(define (mfib-iter a b p q count)
  (cond ((= count 0) b)
        ((even? count)
         (mfib-iter a
                    b   
                    (+ (* p p) (* q q)) 
                    (+ (* q q) (* 2 p q)) 
                    (/ count 2)))
       (else (mfib-iter (+ (* b q) (* a q) (* a p)) 
                         (+ (* b p) (* a q)) 
                         p
                         q
                         (- count 1)))))
(define (mfib n)
  (mfib-iter 1 0 0 1 n)) 
by iwk

タグ:

+ タグ編集
  • タグ:
最終更新:2008年02月29日 17:20
ツールボックス

下から選んでください:

新しいページを作成する
ヘルプ / FAQ もご覧ください。