Exercises 1.43 - 1.46

(ns e1-43-44-45-46
 (:use [util.util :only (repfun avg dx fixed-point average-damp pow close-enough? tolerance square abs avg)])
 (:use [clojure.contrib.test-is :only (deftest is run-tests)])
 (:use [clojure.contrib.generic.math-functions :only (cos)]))

1.43

repfun is defined in util/util.clj

(deftest repfun-test
  (is (= ((repfun inc 4) 6) 10)))

1.44

smooth should return a function which takes an average of three values: f(x - dx), f(x) and f(x + dx).

(defn smooth [f]
  (fn [x]
    (avg (f (- x dx)) (f x) (f (+ x dx)))))

The repeated smooth is trivial.

(defn rep-smooth [f n]
  ((repfun smooth n) f))

1.45

Here we need to find the amount of damping which is needed to average-damp the f(x) = x^n for n > 2. For y = sqrt(x) the damping is needed only once:

y^2 = x => y = x / y

now we have a divergence y0 = y2 = ...:

y1 = x / y0, y2 = x / (x / y0) = y1

which is remedied by an average-damp:

y1 = 1/2 * (y0 + x / y0)

in the general case of y = sqrtn(x)

(repfun (average-damp y) (dec n))

seems to produce the desired results.

(defn sqrt-of-n [x n]
  (fixed-point (repfun
                (average-damp (fn [y] (/ x (pow y (dec n))))) (dec n))
                1))
(deftest test-sqrt
  (is (close-enough? (sqrt-of-n 4 2) 2 tolerance))
  (is (close-enough? (sqrt-of-n 8 3) 2 tolerance))
  (is (close-enough? (sqrt-of-n 16 4) 2 tolerance))
  (is (close-enough? (sqrt-of-n 32 5) 2 tolerance))
  (is (close-enough? (sqrt-of-n 64 6) 2 tolerance)))

1.46

The syntax for letfn is strange... Well, not that strange if you think about it...

(defn iterative-improve [good-enough? improve]
  (fn [x]
    (letfn [(iter [x]
              (let [improved (improve x)]
                (if (good-enough? x improved)
                    improved
                    (recur improved))))]
      (iter x))))

sqrt is fairly straightforward - we use the implementation given in one of the previous chapters.

(defn iterative-sqrt [x]
  ((iterative-improve
    (fn [guess x]
      (let [ratio (/ guess x)]
        (and (< ratio (+ 1 tolerance)) (> ratio (- 1 tolerance)))))
    (fn [guess]
      (avg guess (/ x guess)))) 1))
(deftest test-iter-sqrt
  (is (close-enough? (iterative-sqrt 4) 2 tolerance))
  (is (close-enough? (iterative-sqrt 9) 3 tolerance)))

implementation for fixed-point is not as clear as for sqrt...

(defn iterative-fixed-point [f first-guess]
  ((iterative-improve
    (fn [guess x]
      (< (abs (- guess x)) tolerance))
    (fn [guess]
      (f guess))) first-guess))

See chapter 1.3.3

(deftest test-iter-fp
  (is (close-enough? (iterative-fixed-point cos 1.0) 0.739082 tolerance))
  (is (close-enough? (iterative-fixed-point cos 1.0) (fixed-point cos 1.0) tolerance)))