SICP - Solution: Exercise 1.16

SICP - Solution: Exercise 1.16

October 11, 2018

Exercise 1.16 #

Design a procedure that evolves an iterative exponentiation process that uses successive squaring and uses a logarithmic number of steps, as does fast-expt. (Hint: Using the observation that ${(b^{n/2})^2}={(b^2)^{n/2}}$, keep, along with the exponent $n$ and the base $b$, an additional state variable $a$, and define the state transformation in such a way that the product ${ab^n}$ is unchanged from state to state. At the beginning of the process $a$ is taken to be 1, and the answer is given by the value of $a$ at the end of the process. In general, the technique of defining an invariant quantity that remains unchanged from state to state is a powerful way to think about the design of iterative algorithms.)

Solution #

When $n$ is even, the equation $ab^n$ can rewritten as:

$$ab^n=a{(b^{n/2})^2}=a{(b^2)^{n/2}}=a’b’^{n’}$$

$$a’=a$$ $$b’=b^2$$ $$n’=n/2$$

When $n$ is odd, the equation $ab^n$ can rewritten as:

$$ab^n=abb^{n-1}=(ab)b^{n-1}=a’b’^{n’}$$

$$a’=ab$$ $$b’=b$$ $$n’=n-1$$

This can be implemented directly into:

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

It is easy to check that this is tail recursive by using the tracing function in DrRacket:

#lang racket/base
(require racket/trace)
...
(trace fast-expt-iter)
(fast-expt-iter 1 9 7)

Will evaluate to:

>(fast-expt-iter 1 9 7)
>(fast-expt-iter 9 9 6)
>(fast-expt-iter 9 81 3)
>(fast-expt-iter 729 81 2)
>(fast-expt-iter 729 6561 1)
>(fast-expt-iter 4782969 6561 0)
<4782969

The number of > is representing the depth of the stack.

That can be compared to the recursive version:

#lang racket/base
(require racket/trace)

(define (expt-recurs b n)
  (if (= n 0)
      1
      (* b (expt-recurs b (- n 1)))))

(trace expt-recurs)
(expt-recurs 9 7)

Which returns:

>(expt2 9 7)
> (expt2 9 6)
> >(expt2 9 5)
> > (expt2 9 4)
> > >(expt2 9 3)
> > > (expt2 9 2)
> > > >(expt2 9 1)
> > > > (expt2 9 0)
< < < < 1
< < < <9
< < < 81
< < <729
< < 6561
< <59049
< 531441
<4782969