2011-09-18

SICP Exercise 1.45: Damp Roots

We saw in section 1.3.3 that attempting to compute square roots by naively finding a fixed point of yx/y does not converge, and that this can be fixed by average damping. The same method works for finding cube roots as fixed points of the average-damped yx/y2. Unfortunately, the process does not work for fourth roots -- a single average damp is not enough to make a fixed-point search for yx/y3 converge. On the other hand, if we average damp twice (i.e., use the average damp of the average damp of yx/y3) the fixed-point search does converge. Do some experiments to determine how many average damps are required to compute nth roots as a fixed-point search based upon repeated average damping of yx/yn-1. Use this to implement a simple procedure for computing nth roots using fixed-point, average-damp, and the repeated procedure of exercise 1.43. Assume that any arithmetic operations you need are available as primitives.

First of all we know that the nth root of x can be calculated as the fixed point of the equation yx/yn-1, so let's define a procedure that generates the equivalent lambda expression:
(define (nth-root-function x n)
  (lambda (y) (/ x (expt y (- n 1)))))
And then we can produce some test code for figuring how many average damps we need for a particular root. To do this we want to apply average-damp some number of times to the appropriate nth-root-function expression, and then use that to try to calculate a fixed point. If we're not doing enough average damping then the algorithm will never converge and the interpreter will hang. Here's the test code:
(define (damped-nth-root x n a)
  (if (= a 0)
      (nth-root-function x n)
      ((repeated average-damp a) (nth-root-function x n))))

(define (test-nth-root-damping x n a)
  (fixed-point (damped-nth-root x n a) 1.0))
When we start experimenting with this we quickly find a pattern:

n2 - 34 - 78 - 1516 - 3132 - 63
Required Average Damps12345

Note how the required average damps increases by one each time n reaches the next power of 2. In other words, we want to average damp ⌊log2n⌋ times.

Now let's define a procedure that does this:
(define (nth-root x n)
  (let ((damps (floor (/ (log n) (log 2)))))
    (fixed-point (damped-nth-root x n damps) 1.0)))
And we can check it works:
> (nth-root 4 2)
2.000000000000002
> (nth-root 4 4)
1.414213562373095
> (nth-root 4 8)
1.1892071150032364
> (nth-root 4 16)
1.0905077327148582
> (nth-root 4 32)
1.0442737827236872
> (nth-root 4 64)
1.0218971491473008
> (nth-root 4 128)
1.0108892864974073
> (nth-root 4 256)
1.0054299014117003
> (nth-root 4 512)
1.002711275223178
> (nth-root 4 1024)
1.001354719985141
> (nth-root 4 2048)
1.000677130741309
> (nth-root 4 4096)
1.0003386176117304

No comments:

Post a Comment