本節のべき乗アルゴリズムは, 乗算の繰返しによるべき乗の実行に基づいていた. 同様に整数の乗算を加算の繰返しで実行出来る. 次の乗算手続きは(この言語には加算はあるが, 乗算はないと仮定する)expt手続きに似たものである:
(define (* a b) (if (= b 0) 0 (+ a (* a (- b 1)))))このアルゴリズムはbに線形のステップ数をとる. 加算の他に整数を二倍するdouble演算と(偶数の)整数を2で割るhalve演算もあるとしよう. これらを使い, fast-exptと類似の対数的ステップ数の乗算手続きを設計せよ.
p.25のfast-exptを参考に手続きを定義します.
(require (lib "racket/trace.ss")) (define (double x) (* x 2)) (define (halve x) (/ x 2)) (define (fast-mult a b) (cond ((< b 0) (* -1 (fast-mult a (abs b)))) ((= b 0) 0) ((= b 1) a) ((even? b) (double (fast-mult a (halve b)))) (else (+ a (fast-mult a (- b 1)))))) (trace fast-mult)
fast-exptと同じような構造をしています.
負の数をかけた場合と0をかけた場合の扱いを追加しています.
a×bの計算について, 奇数と偶数の場合に分けて, 計算をどのように進めるかを考えます.
1) bが奇数の場合, b = m+1とする. 次の式が成立する.
2) nが偶数の場合, b = 2mとする. 次の式が成立する.
a×(m+1) = a + (a×m)
2) nが偶数の場合, b = 2mとする. 次の式が成立する.
a×(2m) = double(a×m)
実行結果は次のとおりです.
ようこそ DrRacket, バージョン 6.1 [3m]. 言語: Pretty Big; memory limit: 2048 MB. > (fast-mult 3 45) >(fast-mult 3 45) > (fast-mult 3 44) > >(fast-mult 3 22) > > (fast-mult 3 11) > > >(fast-mult 3 10) > > > (fast-mult 3 5) > > > >(fast-mult 3 4) > > > > (fast-mult 3 2) > > > > >(fast-mult 3 1) < < < < <3 < < < < 6 < < < <12 < < < 15 < < <30 < < 33 < <66 < 132 <135 135 > (fast-mult 4 0) >(fast-mult 4 0) <0 0 > (fast-mult 5 -8) >(fast-mult 5 -8) > (fast-mult 5 8) > >(fast-mult 5 4) > > (fast-mult 5 2) > > >(fast-mult 5 1) < < <5 < < 10 < <20 < 40 <-40 -40 >
トレースの結果から、対数的ステップ数で計算していることが分かります.
0 件のコメント:
コメントを投稿