問題1.16
ベキ乗の計算でO(logn)で解く方法を再帰プロセスではなく、反復プロセスで解く方法。
反復プロセスにするのって、すごい難しい。この問題も全然思いつかず、つい答えを見てしまった。
ヒントにある通り、状態変数aを用意しておいて、a=b^0にセット。それで、反復の間にa=b^nにしてしまう方法を考える。この時に、a*(b^n)が常に一定になるようにする。と言うことで、最初0乗のものをどうやってn乗にするか、と言うのがポイント。上手く言葉では説明できないので、とりあえず表にしてみる。
2^10を計算する場合。
n | 10 | 5 | 4 | 2 | 1 | 0 |
a | 2^0 | 2^0 | 2^2 | 2^2 | 2^2 | 2^10 |
b | 2^1 | 2^2 | 2^2 | 2^4 | 2^8 | 2^8 |
S | 2^0*(2^1)^10 | 2^0*(2^2)^5 | 2^2*(2^2)^4 | 2^2*(2^4)^2 | 2^2*(2^8)^1 | 2^10*(2^8)^0 |
と言うような感じになる。
すなわち、
- nが偶数のとき。a <- a, b <- b^2, n <- n/2
- nが奇数のとき。a <- a*b, b <- b, n <- n-1
と言う感じ。
コードは、
(define (fast-iter b n) (define (square x) (* x x)) (define (even? n) (= (remainder n 2) 0)) (define (iter a b n) (cond ((= n 0) a) ((even? n) (iter a (square b) (/ n 2))) (else (iter (* a b) b (- n 1))))) (iter 1 b n))
となる。
今回は、答えを見ちゃったので、わかったけど、反復プロセスを設計するのは、難しいなぁ。
考え方の糸口すらもわからない場合がある。頭の回転が良くなりたいなぁ。今さら、無理なのかぁ。。。orz