#lang racket
;; 1.16
;; expt-iter is tail-recursive hence iterative
(define (iterative-fast-expt b n)
(define (expt-iter coeff base power)
; the invariant is coeff * base ^ power = b ^ n
(cond [(zero? power) coeff]
[(even? power) (expt-iter coeff (sqr base) (/ power 2))]
[else (expt-iter (* base coeff) (sqr base) (/ (sub1 power) 2))]))
(expt-iter 1 b n))
(iterative-fast-expt 2 10)
;; 1024
(iterative-fast-expt 3 5)
;; 243
(time (iterative-fast-expt 2 1234))
;; cpu time: 0 real time: 0 gc time: 0
;; 295811224608098629060044695716103590786339687135372992239556207050657350796238
;; 924261053812082089933038176093702721248284094494136211066544377518349572681192
;; 920386118201521832389936024879031137085494026686245211006117942703402327660993
;; 170980488874938090231273982538640111837184
;; 1.17
(define (double int) (* int 2))
(define (halve even-int) (quotient even-int 2))
(define (fast-mult a b)
(cond [(= b 1) a]
[(even? b) (fast-mult (double a) (halve b))]
[else (+ a (fast-mult (double a) (halve (sub1 b))))]))
(fast-mult 2 3)
;; 6
(fast-mult 3 4)
;; 12
(time (fast-mult 987654321987654321 123456789123456789))
;; cpu time: 0 real time: 0 gc time: 0
;; 121932631356500531347203169112635269
;; 1.18
;; mult-iter is tail-recursive hence iterative
(define (iterative-fast-mult a b)
(define (mult-iter rem num1 num2)
; the invariant is rem + num1 * num2 = a * b
(cond [(zero? num2) rem]
[(even? num2) (mult-iter rem (double num1) (halve num2))]
[else (mult-iter (+ rem num1) (double num1) (halve (sub1 num2)))]))
(mult-iter 0 a b))
(iterative-fast-mult 2 3)
;; 6
(iterative-fast-mult 3 4)
;; 12
(time (iterative-fast-mult 987654321987654321 123456789123456789))
;; cpu time: 0 real time: 1 gc time: 0
;; 121932631356500531347203169112635269
;; 1.19
(define (exponential-fib n)
(if (< n 2)
n
(+ (exponential-fib (- n 1)) (exponential-fib (- n 2)))))
;; The Fibonacci matrix is T(p, q) where p = 0 and q = 1.
;; T(p, q) is [(p + q, q), (q, p)] and we want to pre-compute T(p, q) ^ 2 as
;; some T(p', q') in order to implement the iterative exponentiation process.
;; T(p, q) ^ 2 = [((p + q) ^ 2 + q ^ 2, q * (p + q) + q * p),
;; (q * (p + q) + q * p, p ^ 2 + q ^ 2)]
;; = [(2 * q ^ 2 + 2 * p * q + p ^ 2, q ^ 2 + 2 * p * q),
;; (q ^ 2 + 2 * p * q, q ^ 2 + p ^ 2)]
;; So p' = q ^ 2 + p ^ 2 and q' = q ^ 2 + 2 * p * q.
(define (logarithmic-fib n)
(define (fib-iter a b p q cnt)
; the invariant is (a, b) acted on by T(p, q) cnt times = (Fib(n + 1), Fib(n))
(cond [(zero? cnt) b]
[(even? cnt) (fib-iter a
b
(+ (sqr p) (sqr q))
(+ (sqr q) (* 2 p q))
(/ cnt 2))]
[else (fib-iter (+ (* b q) (* a q) (* a p))
(+ (* b p) (* a q))
p
q
(sub1 cnt))]))
(fib-iter 1 0 0 1 n))
(time (exponential-fib 30))
;; cpu time: 31 real time: 38 gc time: 0
;; 832040
(time (logarithmic-fib 30))
;; cpu time: 0 real time: 0 gc time: 0
;; 832040
(time (exponential-fib 40))
;; cpu time: 4594 real time: 4608 gc time: 0
;; 102334155
(time (logarithmic-fib 40))
;; cpu time: 0 real time: 1 gc time: 0
;; 102334155
(time (logarithmic-fib 1000))
;; cpu time: 0 real time: 0 gc time: 0
;; 434665576869374564356885276750406258025646605173717804024817290895365554179490
;; 518904038775209689623239873322471161642996440906533187938298969649928516003704
;; 47613779516684922887
Comments