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 (bn/2)2 = (b2)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 abn 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.)In order to help us produce an iterative version Abelson and Sussman provide us with a pretty big hint. Given that (bn/2)2 = (b2)n/2, in what ways can we maintain the invariant quantity abn while changing at least one of a, b and n? Well we can square b if we half n. We can also multiply a by b if we subtract 1 from n. I.e.
- abn = a(b2)n/2
- abn = abbn-1
So the first of these relationships gives us a way to maintain the invariant quantity when n is even while the second gives us a way to maintain it when n is odd. This gives us pretty much all we need to construct our iterative exponentiation process. The iterator itself will maintain a state variable, a, and will apply the above relationships appropriately to update the values of a, b and n until it has reduced n to 0. At this point a will hold the desired value as we have maintained the invariant quantity throughout and we have gone from an initial state of 1.bn to ab0 = a.1 = a.
Here's my implementation:
(define (fast-expt b n) (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))And some examples of it in use:
> (fast-expt 2 5) 32 > (fast-expt 3 2) 9 > (fast-expt 4 10) 1048576 > (fast-expt 10 4) 10000
No comments:
Post a Comment