BLOG ARTICLE 분류 전체보기 | 46 ARTICLE FOUND

  1. 2010.12.15 7일차 - 1.3.1
  2. 2010.12.12 연습문제 1.27
  3. 2010.12.11 6일차 - prime 계산 시간
  4. 2010.12.10 7, 8일차
  5. 2010.12.09 6일차 review
  6. 2010.12.07 6일차
  7. 2010.12.06 5일차
  8. 2010.12.02 Cheat Sheet
  9. 2010.12.02 4일차 - 1.2.3 ~ 1.2.4 - 요약
  10. 2010.11.30 3일차 - 1.2 - 요약

7일차 - 1.3.1

Announce/Chapter.1 2010. 12. 15. 00:39

1.3.1 프로시저를 인자로 받는 프로시저

ex 1.29

Simpson's rule은 f(x)를 a~b로 정적분하는 규칙으로, a, (a+b)/2, b의 3점을 지나는 Lagrange polynomial interpolation(2차 방정식) 하고, 이를 적분한 식으로부터 면적을 계산한다. f(x)의 a~b 구간을 2차 방정식으로 interpolation한 함수를 P(x)라고 하고, a와 b의 중간점((a+b)/2)을 m이라 하면, P(x)의 a~b 구간에서 적분값은 ((b - a) / 6) * (f(a) + 4f(m) + f(b)) 이다.

f(x)의 A~B 구간을 짝수인 n 구간(h=(B-A)/n)으로 나누고(나눈 위치를 x0(=A), x1, x2, ... xn(=B) 이라고 하고), 2 구간씩을 Simpson's rule에 따라 계산하면 정적분 값은 h/3 * (f(x0) + 4*f(x1) + 2*f(x2) + 4*f(x3) + 2*f(x4) + ... + 4*f(xn-1) + f(xn)) 이 되고 이를 SUM으로 표현하면, h/3 * (f(x0) + 4*SUM(f(x2i-1)) + 2*SUM(f(x2)) + f(n)) 이 된다.

SUM을 이용해서 integral-simpson 프로시저를 구할 때 sum 프로시저 호출 시 a와 b 인자를 어떻게 설정하는지에 따라 term과 next 프로시저를 다르게 짤 수 있다. 첫번째는 sum의 a 인자값을 실제 범위의 시작값으로 설정하고 next를 실제 간격만큼 증가시키도록 짠 것이고, 두번째 프로시저는 n만큼 반복한다고 생각하고 sum의 a=0, b=n으로 설정한 후 next 프로시저는 1씩 증가하는 inc 프로시저를 설정한 방법이다.

(integral-simpson cube 0 10 100)를 실행하면 모두 동일한 결과가 나오지만, 첫번째 방법은 내부 term 프로시저의 인자 x가 실수이고, 중간의 cond 조건 비교가 실수 비교를 하게 되므로 테스트 식처러 딱 나눠떨어지지 않는 경우 문제가 생길 수 있다. 또 정수 연산에 비해 속도가 느릴거라 생각된다. 즉 첫번째 보다는 두번째 방법이 더 좋은 방법이다.

;; 이건 a부터 시작해서 h만큼 늘어가는 방법
(define (integral-simpson f a b n)
  (define h (/ (- b a) n))
  (define (term x) ; x = a + kh
    (* (cond ((or (= x a) (= x b)) 1)
             ((odd? (/ (- x a) h)) 4)
             (else 2))
       (f x)))
  (define (next x)
    (+ x h))
  (* (/ h 3.0) (sum term a next b)))
;; (integral-simpson cube 0 10 100) => 2500.0
;; 이건 n만큼 돌린다고 생각하고 짠것. 
(define (integral-simpson-2 f a b n)
  (define h (/ (- b a) n))
  (define (term x)
    (* (cond ((or (= x 0) (= x n)) 1)
             ((odd? x) 4)
             (else 2))
       (f (+ a (* x h)))))
  (* (/ h 3.0) (sum term 0 inc n)))
;; (integral-simpson-2 cube 0 10 100) => 2500.0
ex 1.30
;; iterative process SUM 짜기
(define (sum-i term a next b)
  (define (iter x result)
    (if (> x b)
        result
        (iter (next x) (+ result (term x)))))
  (iter a 0))

;; iterative process sum 테스트
(define (sum-cubes-i a b)
  (sum-i cube a inc b))
ex 1.31

product를 차수높은 프로시저로 짜기

;; a - recursive process
(define (product-r term a next b)
  (if (> a b)
      1
      (* (term a) (product-r term (next a) next b))))
;; (product-r identify 1 inc 10) => 3628800

;; b - iterative process
(define (product-i term a next b)
  (define (iter x result)
    (if (> x b)
        result
        (iter (next x) (* result (term x)))))
  (iter a 1))
;; (product-i identify 1 inc 10) => 3628800

;; c - pi/4 계산하기
;; pi/4 = (2/3)*(4/3)*(4/5)*(6/5)*(6/7)*...
;; 분자는 2 4 4 6 6 8 8 ...
;; i가 홀수면 i+1, 짝수면 i+2
;; 분모는 3 3 5 5 7 7 9 9 ...
;; i가 홀수면 i+2, 짝수면 i+1
(define (pi-over-4 n)
  (define (term a)
    (/ (if (odd? a) (+ a 1.0) (+ a 2))
       (if (odd? a) (+ a 2.0) (+ a 1))))
  (product-i term 1 inc n))
;; (pi-over-4 1000000) => 0.7853985560957135
;; (/ pi 4) => 0.7853981633974483
ex 1.32
;; accumulate 짜기
;; recursive process
(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))))
;; iterative process
(define (accumulate-i combiner null-value term a next b)
  (define (iter x result)
    (if (> x b)
        result
        (iter (next x) (combiner result (term x)))))
  (iter a null-value))

;; product
(define (product-a-r term a next b)
  (accumulate-r * 1 term a next b))
;; (product-a-r identify 1 inc 10) => 3628800
(define (product-a-i term a next b)
  (accumulate-i * 1 term a next b))
;; (product-a-i identify 1 inc 10) => 3628800

;; sum
(define (sum-a-r term a next b)
  (accumulate-r + 0 term a next b))
;; (sum-a-r identify 0 inc 10) => 55
(define (sum-a-i term a next b)
  (accumulate-i + 0 term a next b))
;; (sum-a-i identify 0 inc 10) => 55
ex 1.33
;; filtered-accumulate 짜고 책에 있는 a, b 짜기
(define (filtered-accumulate-r combiner null-value filter term a next b)
  (if (> a b)
      null-value
      (combiner (if (filter a)
                    (term a)
                    null-value)
                (filtered-accumulate-r combiner null-value filter term (next a) next b))))

(define (filtered-accumulate-i combiner null-value filter term a next b)
  (define (iter x result)
    (if (> x b)
        result
        (iter (next x) (combiner result (if (filter x) (term x) null-value)))))
  (iter a null-value))
 
;(filtered-accumulate-r + 0 even? identify 0 inc 10) ; => 30
;(filtered-accumulate-r + 0 odd? identify 0 inc 10)  ; => 25
;(filtered-accumulate-i + 0 even? identify 0 inc 10) ; => 30
;(filtered-accumulate-i + 0 odd? identify 0 inc 10)  ; => 25

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

(define (prime? n)
  (= (smallest-divisor n) n))

(define (smallest-divisor n)
  (define (divides? a b)
    (= (remainder a b) 0))
  (define (square x)
    (* x x))
  (define (find-divisor value test-div)
    (cond ((divides? value test-div) test-div)
          ((> (square test-div) value) value)
          (else (find-divisor value (+ test-div 1)))))
  (find-divisor n 2))

;; a
(define (sum-prime-square a b)
  (filtered-accumulate-i + 0 prime? square a inc b))

;; (sum-prime-square 2 10) => 2*2 + 3*3 + 5*5 + 7*7 = 87

(define (GCD a b)
  (if (= b 0)
      a
      (GCD b (remainder a b))))

;; b
(define (product-seed n)
  (define (filter x)
    (= (GCD x n) 1))
  (filtered-accumulate-i * 1 filter identify 1 inc (- n 1)))
;; (product-seed 10) ;; => (* 1 3 7 9) = 189
AND

(prime?) 프로시저는 항상 소수를 검사하는 올바른 프로시저라고 하면...

(define (prime-by-fermat-all-number? n)
  (define (iter a)
    (if (< a 2) #t
        (if (= (expmod a n n) a) (iter (- a 1)) #f)))
  (iter (- n 1)))
 
(define (camichael-number? n)
  (and (not (prime? n)) (prime-by-fermat-all-number? n)))

; (camichael-number? 11)   => #f
; (camichael-number? 561)  => #t
; (camichael-number? 1105) => #t
; (camichael-number? 1729) => #t
; (camichael-number? 2465) => #t
; (camichael-number? 2821) => #t
; (camichael-number? 6601) => #t
AND

연습문제 1.22

1,000,000,000까지는 sqrt(10), 약 3.2배 가량 증가하는데, 1,000,000,000 이후부터 급격히 증가(20배?). 그 이후로는 대략 비슷해 짐. 연습문제 1.25의 결론처럼 숫자가 커져 연산 속도에 영향을 미친거이라 생각됨.

; 1000           ***    0.004882812500 ***    0.005126953125 ***    0.006103515625
; 10000          ***    0.015869140625 ***    0.017822265625 ***    0.015869140625
; 100000         ***    0.052001953125 ***    0.049072265625 ***    0.051025390625
; 1000000        ***    0.157958984375 ***    0.160888671875 ***    0.162109375000
; 10000000       ***    0.492187500000 ***    0.503906250000 ***    0.485839843750
; 100000000      ***    1.593994140625 ***    2.043945312500 ***    1.531005859375
; 1000000000     ***    5.008789062500 ***    5.659179687500 ***    5.419921875000
; 10000000000    ***   92.404052734375 ***  154.035888671875 ***   91.474121093750
; 100000000000   ***  342.795898437500 ***  344.692138671875 ***  347.473876953125
; 1000000000000  *** 1128.643066406250 *** 1105.849121093750 *** 1112.751953125000
; 10000000000000 *** 3619.240966796875 *** 3515.051025390625 *** 4914.712890625000
연습문제 1.23

+1(연습문제 1.22)에 비해 절반 시간을 보임.

; 1000           ***    0.004150390625 ***    0.005126953125 ***    0.004150390625
; 10000          ***    0.011962890625 ***    0.011962890625 ***    0.012939453125
; 100000         ***    0.041015625000 ***    0.033935546875 ***    0.033935546875
; 1000000        ***    0.116943359375 ***    0.117187500000 ***    0.109863281250
; 10000000       ***    0.344970703125 ***    0.338867187500 ***    0.341796875000
; 100000000      ***    1.219970703125 ***    1.272949218750 ***    1.093994140625
; 1000000000     ***    3.734863281250 ***    3.724121093750 ***    3.524169921875
; 10000000000    ***   48.615966796875 ***   48.451904296875 ***   48.177001953125
; 100000000000   ***  231.741943359375 ***  167.779052734375 ***  173.546875000000
; 1000000000000  ***  631.395996093750 ***  591.827880859375 ***  621.291015625000
; 10000000000000 *** 1892.336181640625 *** 1906.916015625000 *** 1847.104980468750
연습문제 1.24

페르마 테스트를 이용한 prime 계산 시간. 1,000와 1,000,000의 계산 시간이 log n배 차이가 나는가? 그렇다. 참고로 내장된 random 프로시저가 1,000,000,000보다 큰 수에 대해서는 계산을 못하므로 에러 발생.

; 1000       *** 0.802001953125 *** 0.83300781250 *** 0.875976562500
; 10000      *** 1.072998046875 *** 1.02001953125 *** 1.052978515625
; 100000     *** 2.477050781250 *** 2.31689453125 *** 2.307861328125
; 1000000    *** 3.400146484375 *** 3.22607421875 *** 3.428955078125
; 10000000   *** 4.041992187500 *** 4.45117187500 *** 4.256103515625
; 100000000  *** 5.079101562500 *** 4.97900390625 *** 4.998046875000
; 1000000000 *** 5.583984375000 *** 5.29101562500 *** 5.474853515625
(runtime)

Racket에서 실행하려면 (runtime) 말고 (current-inexact-milliseconds)를 사용해야 한다.

;; 1.22
(define (timed-prime-test n)
;  (display n)
;  (newline)
  (start-prime-test n (current-inexact-milliseconds)))

(define (start-prime-test n start-time)
  (if (prime? n) ; 100)
      (report-prime n (- (current-inexact-milliseconds) start-time))
      #f))

(define (report-prime n elapsed-time)
  (display " *** ")
  (display elapsed-time))

(define (search-for-prime n c)
  (if (= c 0)
      (newline)
      (search-for-prime
       (+ n 1)
       (if (timed-prime-test n)
           (- c 1)
           c))))
AND

7, 8일차

Announce/Chapter.1 2010. 12. 10. 14:36
예정 범위 : 1.3.1 ~ 1.3.3

12월 14일 (화)
- 리뷰 : 전현철
- 발표 : 유승근

12월 16일 (목)
- 리뷰 : 이준
- 발표 : 유훈종
AND

6일차 review

Review 2010. 12. 9. 23:42

1.2.6 연습:소수 찾기

소수 찾는 방법은 약수를 이용하는 방법과 페르마 검사를 이용한 확률적 방법 있다. 약수를 이용하는 방법은 계산 단계가 O(sqrt(n)) 이다.

확률적 방법에서는 새롭게 expmod 프로시저를 짜는데 이 프로시저를 주의해서 봐야 한다. expmod는 (base^exp)%m 을 계산하는 프로시저이고, 책에서는 다음과 같이 짜여 있다.

(define (expmod-1 base exp m)
  (cond ((= exp 0) 1)
        ((even? exp)
         (remainder (square (expmod base (/ exp 2) m)) m))
        (else
         (remainder (* base (expmod base (- exp 1) m)) m))))

이 프로시저는 시간은 O(log n), 공간은 O(n)의 복잡도를 가진다. 기존에 짜여진 fastexpt-2 프로시저(연습 문제 1.16)를 이용하면 다음과 같이 짤 수 있고, 이 경우 시간은 O(log n), 공간은 O(1)의 복잡도를 가진다. 이 부분만 볼때는 fastexpt-2 프로시저를 이용하는 것이 좋아 보인다.

(define (expmod-2 base exp m)
  (remainder (fastexpt-2 base exp) m))

연습 문제 1.25가 이 질문인데 참고한 외부 솔루션을 기반으로 정리해 보면,
expmod-1의 경우는 연산을 계속 미루면서 공간이 늘어나는 대신 상태 변수의 값이 증가하지 않고 오히려 값이 감소하는 반면,
fastexpt-2의 경우는 내부 iteration을 돌면서 상태 변수 값이 계속 증가하게 된다.
이상적으로는 값이 크기가 기본 연산(primitive operator)의 실행 속도에 관련이 없어야겠지만, 실제로는 값이 커지면 기본 연산의 속도에 영향을 미치게 되므로 expmod-2가 아닌 expmod-1을 사용해야 한다라고 결론 내릴 수 있다.

expmod-1에 의한 계산 절차는 다음과 같다.

;; e : expmod-1
;; r : remainder
;; s : square
(e 10 20 3)
(r (s (e 10 10 3)) 3)
(r (s (r (s (e 10 5 3)) 3)) 3)
(r (s (r (s (* 10 (e 10 4 3))) 3)) 3)
(r (s (r (s (* 10 (r (s (e 10 2 3)) 3))) 3)) 3)
(r (s (r (s (* 10 (r (s (r (s (e 10 1 3)) 3)) 3))) 3)) 3)
(r (s (r (s (* 10 (r (s (r (s (r (* 10 (e 10 1 3)) 3)) 3)) 3))) 3)) 3)
(r (s (r (s (* 10 (r (s (r (s (r (* 10 (r (* 10 (e 10 0 3)) 3)) 3)) 3)) 3))) 3)) 3)
(r (s (r (s (* 10 (r (s (r (s (r (* 10 (r (* 10 1) 3)) 3)) 3)) 3))) 3)) 3)
(r (s (r (s (* 10 (r (s (r (s (r (* 10 (r 10 3)) 3)) 3)) 3))) 3)) 3)
(r (s (r (s (* 10 (r (s (r (s (r (* 10 1) 3)) 3)) 3))) 3)) 3)
(r (s (r (s (* 10 (r (s (r (s (r 10 3)) 3)) 3))) 3)) 3)
(r (s (r (s (* 10 (r (s (r (s 1) 3)) 3))) 3)) 3)
(r (s (r (s (* 10 (r (s (r 1 3)) 3))) 3)) 3)
(r (s (r (s (* 10 (r (s 1) 3))) 3)) 3)
(r (s (r (s (* 10 (r 1 3))) 3)) 3)
(r (s (r (s (* 10 1)) 3)) 3)
(r (s (r (s 10) 3)) 3)
(r (s (r 100 3)) 3)
(r (s 1) 3)
(r 1 3)
1

expmod-2에 의한 계산 절차는 다음과 같다.

;; iter는 내부에서 반복 프로세스로 동작하는 프로시저
(remainder (fastexpt-2 4 6) 3)
(iter 1 4 6)
(iter 1 16 3)
(iter 16 16 2)
(iter 16 256 1)
(iter 4096 256 0)
4096

프로세스와 같이 expmod-1은 공간은 늘어났다 줄어드는 반면, 값의 크지 않고,expmod-2는 공간의 동일하나 값이 계속 커진다.

AND

6일차

Announce/Chapter.1 2010. 12. 7. 19:47
시간: 2010.12.9 PM 6:30

<복습>
범위: 1.2.5 ~ 1.2.6
발표: 유승근

<진도>
범위: 1.2.6 연습문제
발표: 정다정
AND

5일차

Announce/Chapter.1 2010. 12. 6. 14:16
시간: 2010.12.7 PM 6:30

<복습>
범위: 1.2.3 ~ 1.2.4
발표: 유훈종

<진도>
범위: 1.2.5 ~ 1.2.6
발표: 이준
AND

Cheat Sheet

Reference 2010. 12. 2. 01:28
Lisp: Common Lisp, Scheme, Clojure, Emacs Lisp 치트시트

막히고 답답할땐 열어보아요~~
AND

1.2.3 프로세스가 자라나는 정도
  • Order of growth, 자람차수 : 입력의 크기에 따라 프로세스가 쓰는 자원양이 자라나는 정도
  • Θ(f(n)), theta of f(n) : n 알맞게 큰값, 그에 대해 처리되는 함수 f(n) 이 있을 때 f(n) 의 theta 만큼 단계 또는 기억 공간이 필요하다는 것을 표기
  • Θ(1)
  • Θ(n), Θ(2n), Θ(100n) 과 같이 단순상수는 큰 영향이 없음 (간추려 말할 수 있다). 즉, 자람 차수는 프로세스가 쓰는 자원 양을 어림잡아 나타내는 것일 뿐이다.
  • Θ(n^2) 등등의 형을 띄는 단계로 표현 할 수 있다.
  • 로그,logarithmic 자람 차수 Θ(log n) 띄는 알고리즘을 보자.

- 연습문제 1.15
;;EXERCISE 1.15
(define (cube x) (* x x x))

(define (p x) 
  (display "; call p\n")
  (- (* 3 x) (* 4 (cube x))))

(define (sine angle)
   (if (not (> (abs angle) 0.1))
       angle
       (p (sine (/ angle 3.0)))))
  • "충분히 작은 각"을 만족하는 상황을 식으로 풀어보면
  • -0.1 <= a(1/3)^n <= 0.1
  • 위 식을 정리하면 (log 표기를 정확히 어떻게 해야하는지 모르겠네요;;)
  • n = log(3, 10 * a)


1.2.4 거듭제곱
같은 수를 여러번 곱하는 (거듭제곱) 문제의 재귀 규칙을 간단히 보면,
  • b^n = b * ( b ^ (n - 1) )
  • b^0 = 1
이 규칙에 따른 프로시저는 아래와 같이 계산단계, 기억공간 모두 Θ(n)
;; Linear recursion
;; Θ(n), Θ(n)
(define (expt b n)
  (if (= n 0)
      1
      (* b (expt b (- n 1)))))
이를 되도는 프로세스로 표현하면 각각 Θ(n), Θ(1) 만큼 사용한다.
;; Linear iteration
;; Θ(n), Θ(1)
(define (expt b n)
  (expt-iter b n 1))

(define (expt-iter b counter product)
  (if (= counter 0)
      product
      (expt-iter b
                (- counter 1)
                (* b product)))) 
하지만 단계를 절반씩 잘라나가는 아래 규칙을 참조하면 log n 단계로 줄일 수 있을 것이다.
(8번 곱해야할 과정을 3번으로 줄였다)
  • b^2 = b * b
  • b^4 = (b^2 * b^2)
  • b^8 = (b^4 * b^4)

규칙을 다듬어서 지수 n 이 짝수, 홀수일 경우로 나누어 생각하면 아래의 프로시저를 생각할 수 있다.
;; Logarithmic iteration
(define (fast-expt b n)
  (cond ((= n 0) 1)
        ((even? n) (square (fast-expt b (/ n 2))))
        (else (* b (fast-expt b (- n 1))))))

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

- 연습문제 1.16
;; EXERCISE 1.16
(define (proc-expt b n)
  (define (iter b n a)
    (cond ((= n 0) a)
          ((even? n) (iter (square b) (/ n 2) a))
          (else (iter b (- n 1) (* a b)))))
  (iter b n 1)
)

- 연습문제 1.17
;; EXERCISE 1.17
(define (custom-mult a b)
  (if (= b 0)
      0
      (+ a (custom-mult a (- b 1)))))

(define (double x)
  (* x 2))
(define (halve x)
  (/ x 2))

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

; (fast-mult 3 5)
; (+ 3 (fast-mult 3 4))
; (+ 3 (double (fast-mult 3 2)))
; (+ 3 (double (double (fast-mult 3 1))))
; (+ 3 (double (double 3)))
; (+ 3 (double 6))
; (+ 3 12)

- 연습문제 1.18
;; EXERCISE 1.18
(define (proc-mult b n)
  (define (iter b n a)
    (cond ((= n 0) a)
          ((even? n) (iter (double b) (halve n) a))
          (else (iter b (- n 1) (+ a b)))))
  (iter b n 0)
)
AND

1.2 프로시저와 프로세스

;
;; 어떤 문제를 풀기 위해 어떤 식으로 프로그래밍 언어를 써야 하는지 모르는 상태다.
;; 어떤 프로시저를 정의해야 하는데 프로시저를 돌릴 때 어떤 결과가 나오는지 미리 그려낼 줄 아는 경험 부족한 상태.
;; 프로시저: 한 컴퓨터 프로세스가 어떻게 나아가는지 밝힌 것.
;; 프로시저가 만들어내는 프로세스의 몇가지 꼴(shape)의 보기를 들것이다.
;

1.2.1 되돌거나 반복하는 프로세스

;
;; 되도는 프로세스 recursion
;;  - 연산을 바로 수행하지 못하고 뒤로 미루는(deferred operation) 모양
;; 반복하는 프로세스 iterative
;;  - 상태변수 존재. 계산의 크기가 늘어나지 않는다.
;; 되도는 프로세스와 되도는 프로시저
;;  - 프로시저는 되도는 모양이더라도(자신을 다시 호출) 프로세스는 그렇지 않을 수 있다. - linera iterative process
;; tail recursion : 꼬리에서 자기 자신을 다시 호출하면서 recursive process가 안되도록 하는 것.
;;  - http://en.wikipedia.org/wiki/Recursion_%28computer_science%29#Tail-recursive_functions

;; fact(n) = n * (n -1) * (n-2) * ... * 2 * 1
(define (fact1 n)
  (if (= n 1)
      1
      (* n (fact1 (- n 1)))))

;; recursive process
;; (fact1 4)
;; (* 4 (fact 3))
;; (* 4 (* 3 (fact 2)))
;; (* 4 (* 3 (* 2 (fact 1))))
;; (* 4 (* 3 (* 2 1)))
;; (* 4 (* 3 2))
;; (* 4 6)
;; 24

;; iterative process
;; product < counter * product
;; counter < counter - 1
(define (fact2 n)
  (define (iter p c)
    (if (= c 1)
      p
      (iter (* p c) (- c 1))))
  (iter 1 n))

;; (fact2 4)
;; (iter 1 4)
;; (iter 4 3)
;; (iter 12 2)
;; (iter 24 1)
;; 24

;; ex 1.9

;; (+ 4 5)
;; (inc (+ 3 5))
;; (inc (inc (+ 2 5)))
;; (inc (inc (inc (+ 1 5))))
;; (inc (inc (inc (inc (+ 0 5)))))
;; (inc (inc (inc (inc 5)))))
;; (inc (inc (inc 6)))
;; (inc (inc 7))
;; (inc 8)
;; 9

(define (inc a)
  (+ a 1))

(define (dec a)
  (- a 1))

(define (plus-1 a b)
  (if (= a 0)
      b
      (inc (plus-1 (dec a) b))))

;; (plus-1 2 3)
;; (inc (plus-1 1 3))
;; (inc (inc (plus-1 0 3)))
;; (inc (inc 3))
;; (inc 4)
;; 5

(define (plus-2 a b)
  (if (= a 0)
      b
      (plus-2 (dec a) (inc b))))
;; (plus-2 2 3)
;; (plus-2 1 4)
;; (plus-2 0 5)
;; 5

;; ex 1.10
;; 애커만 함수 http://en.wikipedia.org/wiki/Ackermann_function
;; primitive recursive function은 아니지만 total computable function
;; primitive recursive function은 항상 total computable function이다.
;; A(x, y)
;; 0                      if y = 0
;; 2 * y                  if x = 0
;; 2                      if y = 2
;; A(x - 1, A(x, y - 1))
(define (A x y)
  (cond ((= y 0) 0)
        ((= x 0) (* 2 y))
        ((= y 1) 2)
        (else (A (- x 1)
                 (A x (- y 1))))))

;; (A 0 n) : (* 2 n)
;; (A 1 n) : (exp 2 n)
;; (A 2 n) : n = 1 이면 1
;;           n > 1 이면 (exp 2 (exp 2 (exp 2 ... 2))) -> n번 반복
;; (A 3 n) : n = 1 이면 1
;;           n > 1 이면 ???
;

1.2.2 여러 갈래로 되도는 프로세스

;
;; 피보나치 수열 f(n) = f(n-1) + f(n-2), f(0) = 0, f(1) = 1
;;
;; 0 -> 0
;; 1 -> 1
;; recursive process
(define (fib1 n)
  (cond ((= n 0) 0)
        ((= n 1) 1)
        (else (+ (fib1 (- n 1)) (fib1 (- n 2))))))

;; fib1 -> n -> pi^n / root(5)

;; f(n) = f(n-1) + f(n-2)
;; iterative process
(define (fib2 n)
  (define (iter a b c)
    (if (= c 0)
        b
        (iter (+ a b) a (- c 1))))
  (iter 1 0 n))
;; (fib 4)
;; (iter 1 0 4)
;; (iter 1 1 3)
;; (iter 2 1 2)
;; (iter 3 2 1)
;; (iter 5 3 0)
;; 3

;; 돈 바꾸는 방법 ??? - review 할 때 다시 얘기해 봅시다.
;; 받은 돈을 동전으로 바꾸는 방법
;; 10 센트
;; 1 센트 * 10
;; 5 센트 * 2
;; 5 센트 + 1 센트 * 5

(define (count-change amount)
  (cc amount 5))

(define (cc amount kinds-of-coins)
  (cond ((= amount 0) 1)
        ((or (< amount 0) (= kinds-of-coins 0)) 0)
        (else (+ (cc amount (- kinds-of-coins 1))
                 (cc (- amount (first-denomination kinds-of-coins)) kinds-of-coins)))))

(define (first-denomination kinds)
  (cond ((= kinds 1) 1)
        ((= kinds 2) 5)
        ((= kinds 3) 10)
        ((= kinds 4) 25)
        ((= kinds 5) 50)))

;; ex 1.11
(define (F1 n)
  (if (< n 3)
      n
      (+ (F1 (- n 1)) (* (F1 (- n 2)) 2) (* (F1 (- n 3)) 3))))

;; a < a + 2*b + 3c
;; b < a 
;; c < b
(define (F2 n)
  (define (iter x y z count)
    (if (< count 3)
        x
        (iter (+ x (* y 2) (* z 3)) x y (- count 1))))
  (iter 2 1 0 n))

;; f(0) = 0
;; f(1) = 1
;; f(2) = 2
;; f(3) = f(2) + 2f(1) + 3f(0) = 4

;; ex 1.12
;; pascal's triangle,
;; p(r, c) = p(r-1, c-1) + p(r-1, c)
;; p(r, 1) = 1, p(r, r) = 1
(define (pt r c)
  (cond ((or (= c 1) (= r c)) 1)
        ((or (< c 0) (< r 0) (> c r)) 0)
        (else (+ (pt (- r 1) (- c 1))
                 (pt (- r 1) c)))))
;
AND