mirror of
https://github.com/correl/sicp.git
synced 2024-11-23 11:09:57 +00:00
716 lines
24 KiB
Org Mode
716 lines
24 KiB
Org Mode
#+BEGIN_HTML
|
|
---
|
|
title: 1.3 - Formulating Abstractions with Higher-Order Procedures
|
|
layout: org
|
|
---
|
|
#+END_HTML
|
|
|
|
* Procedures as Arguments
|
|
|
|
#+BEGIN_SRC scheme :tangle yes
|
|
;; ===================================================================
|
|
;; 1.3.1: Procedures as Arguments
|
|
;; ===================================================================
|
|
|
|
(define (sum term a next b)
|
|
(if (> a b)
|
|
0
|
|
(+ (term a)
|
|
(sum term (next a) next b))))
|
|
|
|
(define (inc n) (+ n 1))
|
|
|
|
(define (cube n) (* n n n))
|
|
|
|
(define (sum-cubes a b)
|
|
(sum cube a inc b))
|
|
|
|
(define (identity x) x)
|
|
|
|
(define (sum-integers a b)
|
|
(sum identity a inc b))
|
|
|
|
(define (pi-sum a b)
|
|
(define (pi-term x)
|
|
(/ 1.0 (* x (+ x 2))))
|
|
(define (pi-next x)
|
|
(+ x 4))
|
|
(sum pi-term a pi-next b))
|
|
|
|
(define (integral f a b dx)
|
|
(define (add-dx x) (+ x dx))
|
|
(* (sum f (+ a (/ dx 2.0)) add-dx b)
|
|
dx))
|
|
|
|
#+END_SRC
|
|
|
|
** Exercise 1.29
|
|
Simpson's Rule is a more accurate method of numerical integration
|
|
than the method illustrated above. Using Simpson's Rule, the
|
|
integral of a function f between a and b is approximated as
|
|
|
|
#+BEGIN_EXAMPLE
|
|
h
|
|
- (y_0 + 4y_1 + 2y_2 + 4y_3 + 2y_4 + ... + 2y_(n-2) + 4y_(n-1) + y_n)
|
|
3
|
|
#+END_EXAMPLE
|
|
|
|
where h = (b - a)/n, for some even integer n, and y_k = f(a + kh).
|
|
(Increasing n increases the accuracy of the approximation.) Define
|
|
a procedure that takes as arguments f, a, b, and n and returns the
|
|
value of the integral, computed using Simpson's Rule. Use your
|
|
procedure to integrate `cube' between 0 and 1 (with n = 100 and n =
|
|
1000), and compare the results to those of the `integral' procedure
|
|
shown above.
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
#+BEGIN_SRC scheme :tangle yes
|
|
;; -------------------------------------------------------------------
|
|
;; Exercise 1.29
|
|
;; -------------------------------------------------------------------
|
|
|
|
(define (simpson-integral f a b n)
|
|
(define h (/ (- b a) n))
|
|
(define (y k)
|
|
(f (+ a (* k h))))
|
|
(define (simpson-term x)
|
|
(cond ((= x 0) (y x))
|
|
((= x n) (y x))
|
|
((even? x) (* 2 (y x)))
|
|
((odd? x) (* 4 (y x)))))
|
|
(* (/ h 3) (sum simpson-term 0 inc n)))
|
|
#+END_SRC
|
|
|
|
** Exercise 1.30
|
|
The `sum' procedure above generates a linear recursion. The
|
|
procedure can be rewritten so that the sum is performed
|
|
iteratively. Show how to do this by filling in the missing
|
|
expressions in the following definition:
|
|
|
|
#+BEGIN_SRC scheme
|
|
(define (sum term a next b)
|
|
(define (iter a result)
|
|
(if <??>
|
|
<??>
|
|
(iter <??> <??>)))
|
|
(iter <??> <??>))
|
|
#+END_SRC
|
|
|
|
---
|
|
|
|
#+BEGIN_SRC scheme :tangle yes
|
|
;; -------------------------------------------------------------------
|
|
;; Exercise 1.30
|
|
;; -------------------------------------------------------------------
|
|
|
|
(define (sum term a next b)
|
|
(define (iter a result)
|
|
(if (> a b)
|
|
result
|
|
(iter (next a) (+ (term a) result))))
|
|
(iter a 0))
|
|
|
|
#+END_SRC
|
|
|
|
** Exercise 1.31
|
|
a. The `sum' procedure is only the simplest of a vast number of
|
|
similar abstractions that can be captured as higher-order
|
|
procedures.(3) Write an analogous procedure called `product'
|
|
that returns the product of the values of a function at
|
|
points over a given range. Show how to define `factorial' in
|
|
terms of `product'. Also use `product' to compute
|
|
approximations to [pi] using the formula(4)
|
|
|
|
#+BEGIN_EXAMPLE
|
|
pi 2 * 4 * 4 * 6 * 6 * 8 ...
|
|
-- = -------------------------
|
|
4 3 * 3 * 5 * 5 * 7 * 7 ...
|
|
#+END_EXAMPLE
|
|
|
|
b. If your `product' procedure generates a recursive process,
|
|
write one that generates an iterative process. If it
|
|
generates an iterative process, write one that generates a
|
|
recursive process.
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
#+BEGIN_SRC scheme :tangle yes
|
|
;; -------------------------------------------------------------------
|
|
;; Example 1.31
|
|
;; -------------------------------------------------------------------
|
|
|
|
(define (product-recursive term a next b)
|
|
(if (> a b)
|
|
1
|
|
(* (term a)
|
|
(product-recursive term (next a) next b))))
|
|
|
|
(define (product-iter term a next b)
|
|
(define (iter a result)
|
|
(if (> a b)
|
|
result
|
|
(iter (next a) (* (term a) result))))
|
|
(iter a 1))
|
|
#+END_SRC
|
|
|
|
** Exercise 1.32
|
|
a. Show that `sum' and `product' (*Note Exercise 1-31::) are
|
|
both special cases of a still more general notion called
|
|
`accumulate' that combines a collection of terms, using some
|
|
general accumulation function:
|
|
|
|
#+BEGIN_SRC scheme
|
|
(accumulate combiner null-value term a next b)
|
|
#+END_SRC
|
|
|
|
`Accumulate' takes as arguments the same term and range
|
|
specifications as `sum' and `product', together with a
|
|
`combiner' procedure (of two arguments) that specifies how
|
|
the current term is to be combined with the accumulation of
|
|
the preceding terms and a `null-value' that specifies what
|
|
base value to use when the terms run out. Write `accumulate'
|
|
and show how `sum' and `product' can both be defined as
|
|
simple calls to `accumulate'.
|
|
|
|
b. If your `accumulate' procedure generates a recursive process,
|
|
write one that generates an iterative process. If it
|
|
generates an iterative process, write one that generates a
|
|
recursive process.
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
#+BEGIN_SRC scheme :tangle yes
|
|
;; -------------------------------------------------------------------
|
|
;; Example 1.32
|
|
;; -------------------------------------------------------------------
|
|
|
|
(define (accumulate-recursive combiner null-value term a next b)
|
|
(if (> a b)
|
|
null-value
|
|
(combiner (term a)
|
|
(accumulate-recursive combiner null-value term (next a) next b))))
|
|
|
|
(define (accumulate-iter combiner null-value term a next b)
|
|
(define (iter a result)
|
|
(if (> a b)
|
|
result
|
|
(iter (next a) (combiner (term a) result))))
|
|
(iter a null-value))
|
|
|
|
(define (sum term a next b)
|
|
(accumulate-iter + 0 term a next b))
|
|
|
|
(define (product term a next b)
|
|
(accumulate-iter * 1 term a next b))
|
|
#+END_SRC
|
|
|
|
** Exercise 1.33
|
|
You can obtain an even more general version of
|
|
`accumulate' (*Note Exercise 1-32::) by introducing the notion of
|
|
a "filter" on the terms to be combined. That is, combine only
|
|
those terms derived from values in the range that satisfy a
|
|
specified condition. The resulting `filtered-accumulate'
|
|
abstraction takes the same arguments as accumulate, together with
|
|
an additional predicate of one argument that specifies the filter.
|
|
Write `filtered-accumulate' as a procedure. Show how to express
|
|
the following using `filtered-accumulate':
|
|
|
|
a. the sum of the squares of the prime numbers in the interval a
|
|
to b (assuming that you have a `prime?' predicate already
|
|
written)
|
|
|
|
b. the product of all the positive integers less than n that are
|
|
relatively prime to n (i.e., all positive integers i < n such
|
|
that GCD(i,n) = 1).
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
#+BEGIN_SRC scheme :tangle yes
|
|
;; -------------------------------------------------------------------
|
|
;; Example 1.33
|
|
;; -------------------------------------------------------------------
|
|
|
|
(define (accumulate-filter predicate combiner null-value term a next b)
|
|
(define (iter a result)
|
|
(cond ((> a b) result)
|
|
((predicate a) (iter (next a) (combiner (term a) result)))
|
|
(else (iter (next a) result))))
|
|
(iter a null-value))
|
|
|
|
#+END_SRC
|
|
|
|
* Constructing Procedures Using `Lambda'
|
|
** Exercise 1.34:
|
|
Suppose we define the procedure
|
|
|
|
#+BEGIN_SRC scheme
|
|
(define (f g)
|
|
(g 2))
|
|
#+END_SRC
|
|
|
|
Then we have
|
|
|
|
#+BEGIN_SRC scheme
|
|
(f square)
|
|
4
|
|
|
|
(f (lambda (z) (* z (+ z 1))))
|
|
6
|
|
#+END_SRC
|
|
|
|
What happens if we (perversely) ask the interpreter to evaluate
|
|
the combination `(f f)'? Explain.
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
The call will fail, as ~(g 2)~ will evaluate to the form ~(2 2)~,
|
|
which will fail to apply as ~2~ is a number, not a procedure.
|
|
|
|
#+BEGIN_SRC scheme
|
|
(f f)
|
|
(f (f 2))
|
|
(f (2 2))
|
|
;; The object 2 is not applicable.
|
|
#+END_SRC
|
|
|
|
* Procedures as General Methods
|
|
#+BEGIN_SRC scheme :tangle yes
|
|
;; -------------------------------------------------------------------
|
|
;; 1.3.3: Procedures as General Methods
|
|
;; -------------------------------------------------------------------
|
|
|
|
(define (average x y)
|
|
(/ (+ x y) 2))
|
|
|
|
(define (search f neg-point pos-point)
|
|
(let ((midpoint (average neg-point pos-point)))
|
|
(if (close-enough? neg-point pos-point)
|
|
midpoint
|
|
(let ((test-value (f midpoint)))
|
|
(cond ((positive? test-value)
|
|
(search f neg-point midpoint))
|
|
((negative? test-value)
|
|
(search f midpoint pos-point))
|
|
(else midpoint))))))
|
|
|
|
(define (close-enough? x y)
|
|
(< (abs (- x y)) 0.001))
|
|
|
|
(define (half-interval-method f a b)
|
|
(let ((a-value (f a))
|
|
(b-value (f b)))
|
|
(cond ((and (negative? a-value) (positive? b-value))
|
|
(search f a b))
|
|
((and (negative? b-value) (positive? a-value))
|
|
(search f b a))
|
|
(else
|
|
(error "Values are not of opposite sign" a b)))))
|
|
|
|
(define tolerance 0.00001)
|
|
|
|
(define (fixed-point f first-guess)
|
|
(define (close-enough? v1 v2)
|
|
(< (abs (- v1 v2)) tolerance))
|
|
(define (try guess)
|
|
(let ((next (f guess)))
|
|
(if (close-enough? guess next)
|
|
next
|
|
(try next))))
|
|
(try first-guess))
|
|
|
|
(define (sqrt x)
|
|
(fixed-point (lambda (y) (average y (/ x y)))
|
|
1.0))
|
|
|
|
#+END_SRC
|
|
** Exercise 1.35:
|
|
Show that the golden ratio [phi] (section *Note 1-2-2::) is a fixed
|
|
point of the transformation x |-> 1 + 1/x, and use this fact to
|
|
compute [phi] by means of the `fixed-point' procedure.
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
#+BEGIN_SRC scheme :tangle yes
|
|
;; -------------------------------------------------------------------
|
|
;; Exercise 1.35
|
|
;; -------------------------------------------------------------------
|
|
|
|
(define phi
|
|
(fixed-point (lambda (x) (+ 1 (/ 1 x)))
|
|
1.0))
|
|
#+END_SRC
|
|
** Exercise 1.36:
|
|
Modify `fixed-point' so that it prints the sequence of
|
|
approximations it generates, using the `newline' and `display'
|
|
primitives shown in *Note Exercise 1-22::. Then find a solution to
|
|
x^x = 1000 by finding a fixed point of x |-> `log'(1000)/`log'(x).
|
|
(Use Scheme's primitive `log' procedure, which computes natural
|
|
logarithms.) Compare the number of steps this takes with and
|
|
without average damping. (Note that you cannot start `fixed-point'
|
|
with a guess of 1, as this would cause division by `log'(1) = 0.)
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
#+BEGIN_SRC scheme :tangle yes
|
|
;; -------------------------------------------------------------------
|
|
;; Exercise 1.36
|
|
;; -------------------------------------------------------------------
|
|
|
|
(define (fixed-point-display f first-guess)
|
|
(define (close-enough? v1 v2)
|
|
(< (abs (- v1 v2)) tolerance))
|
|
(define (try guess)
|
|
(let ((next (f guess)))
|
|
(display (list "Trying" next))
|
|
(newline)
|
|
(if (close-enough? guess next)
|
|
next
|
|
(try next))))
|
|
(try first-guess))
|
|
|
|
(fixed-point-display
|
|
(lambda (x) (/ (log 1000) (log x)))
|
|
1.5)
|
|
|
|
;(Trying 17.036620761802716)
|
|
;(Trying 2.436284152826871)
|
|
;(Trying 7.7573914048784065)
|
|
;(Trying 3.3718636013068974)
|
|
;(Trying 5.683217478018266)
|
|
;(Trying 3.97564638093712)
|
|
;(Trying 5.004940305230897)
|
|
;(Trying 4.2893976408423535)
|
|
;(Trying 4.743860707684508)
|
|
;(Trying 4.437003894526853)
|
|
;(Trying 4.6361416205906485)
|
|
;(Trying 4.503444951269147)
|
|
;(Trying 4.590350549476868)
|
|
;(Trying 4.532777517802648)
|
|
;(Trying 4.570631779772813)
|
|
;(Trying 4.545618222336422)
|
|
;(Trying 4.562092653795064)
|
|
;(Trying 4.551218723744055)
|
|
;(Trying 4.558385805707352)
|
|
;(Trying 4.553657479516671)
|
|
;(Trying 4.55677495241968)
|
|
;(Trying 4.554718702465183)
|
|
;(Trying 4.556074615314888)
|
|
;(Trying 4.555180352768613)
|
|
;(Trying 4.555770074687025)
|
|
;(Trying 4.555381152108018)
|
|
;(Trying 4.555637634081652)
|
|
;(Trying 4.555468486740348)
|
|
;(Trying 4.555580035270157)
|
|
;(Trying 4.555506470667713)
|
|
;(Trying 4.555554984963888)
|
|
;(Trying 4.5555229906097905)
|
|
;(Trying 4.555544090254035)
|
|
;(Trying 4.555530175417048)
|
|
;(Trying 4.555539351985717)
|
|
;;Value: 4.555539351985717
|
|
;
|
|
(fixed-point-display
|
|
(lambda (x) (average x (/ (log 1000) (log x))))
|
|
1.5)
|
|
|
|
;(Trying 9.268310380901358)
|
|
;(Trying 6.185343522487719)
|
|
;(Trying 4.988133688461795)
|
|
;(Trying 4.643254620420954)
|
|
;(Trying 4.571101497091747)
|
|
;(Trying 4.5582061760763715)
|
|
;(Trying 4.555990975858476)
|
|
;(Trying 4.555613236666653)
|
|
;(Trying 4.555548906156018)
|
|
;(Trying 4.555537952796512)
|
|
;(Trying 4.555536087870658)
|
|
;;Value: 4.555536087870658
|
|
|
|
#+END_SRC
|
|
** Exercise 1.37:
|
|
a. An infinite "continued fraction" is an expression of the form
|
|
|
|
#+BEGIN_EXAMPLE
|
|
N_1
|
|
f = ---------------------
|
|
N_2
|
|
D_1 + ---------------
|
|
N_3
|
|
D_2 + ---------
|
|
D_3 + ...
|
|
#+END_EXAMPLE
|
|
|
|
As an example, one can show that the infinite continued
|
|
fraction expansion with the n_i and the D_i all equal to 1
|
|
produces 1/[phi], where [phi] is the golden ratio (described
|
|
in section *Note 1-2-2::). One way to approximate an
|
|
infinite continued fraction is to truncate the expansion
|
|
after a given number of terms. Such a truncation--a
|
|
so-called finite continued fraction "k-term finite continued
|
|
fraction"--has the form
|
|
|
|
#+BEGIN_EXAMPLE
|
|
N_1
|
|
-----------------
|
|
N_2
|
|
D_1 + -----------
|
|
... N_K
|
|
+ -----
|
|
D_K
|
|
#+END_EXAMPLE
|
|
|
|
Suppose that `n' and `d' are procedures of one argument (the
|
|
term index i) that return the n_i and D_i of the terms of the
|
|
continued fraction. Define a procedure `cont-frac' such that
|
|
evaluating `(cont-frac n d k)' computes the value of the
|
|
k-term finite continued fraction. Check your procedure by
|
|
approximating 1/[phi] using
|
|
|
|
#+BEGIN_SRC scheme
|
|
(cont-frac (lambda (i) 1.0)
|
|
(lambda (i) 1.0)
|
|
k)
|
|
#+END_SRC
|
|
|
|
for successive values of `k'. How large must you make `k' in
|
|
order to get an approximation that is accurate to 4 decimal
|
|
places?
|
|
|
|
b. If your `cont-frac' procedure generates a recursive process,
|
|
write one that generates an iterative process. If it
|
|
generates an iterative process, write one that generates a
|
|
recursive process.
|
|
|
|
** Exercise 1.38:
|
|
In 1737, the Swiss mathematician Leonhard Euler published a memoir
|
|
`De Fractionibus Continuis', which included a continued fraction
|
|
expansion for e - 2, where e is the base of the natural logarithms.
|
|
In this fraction, the n_i are all 1, and the D_i are successively
|
|
1, 2, 1, 1, 4, 1, 1, 6, 1, 1, 8, .... Write a program that uses
|
|
your `cont-frac' procedure from *Note Exercise 1-37:: to
|
|
approximate e, based on Euler's expansion.
|
|
|
|
** Exercise 1.39:
|
|
A continued fraction representation of the tangent function was
|
|
published in 1770 by the German mathematician J.H. Lambert:
|
|
|
|
#+BEGIN_EXAMPLE
|
|
x
|
|
tan x = ---------------
|
|
x^2
|
|
1 - -----------
|
|
x^2
|
|
3 - -------
|
|
5 - ...
|
|
|
|
#+END_EXAMPLE
|
|
|
|
where x is in radians. Define a procedure `(tan-cf x k)' that
|
|
computes an approximation to the tangent function based on
|
|
Lambert's formula. `K' specifies the number of terms to compute,
|
|
as in *Note Exercise 1-37::.
|
|
|
|
* Procedures as Returned Values
|
|
#+BEGIN_SRC scheme :tangle yes
|
|
;; -------------------------------------------------------------------
|
|
;; 1.3.4: Procedures as Returned Values
|
|
;; -------------------------------------------------------------------
|
|
|
|
(define (average-damp f)
|
|
(lambda (x) (average x (f x))))
|
|
|
|
(define (sqrt x)
|
|
(fixed-point (average-damp (lambda (y) (/ x y)))
|
|
1.0))
|
|
|
|
(define (cube-root x)
|
|
(fixed-point (average-damp (lambda (y) (/ x (square y))))
|
|
1.0))
|
|
|
|
(define (deriv g)
|
|
(lambda (x)
|
|
(/ (- (g (+ x dx)) (g x))
|
|
dx)))
|
|
(define dx 0.00001)
|
|
|
|
(define (cube x) (* x x x))
|
|
|
|
(define (newton-transform g)
|
|
(lambda (x)
|
|
(- x (/ (g x) ((deriv g) x)))))
|
|
|
|
(define (newtons-method g guess)
|
|
(fixed-point (newton-transform g) guess))
|
|
|
|
(define (sqrt x)
|
|
(newtons-method (lambda (y) (- (square y) x))
|
|
1.0))
|
|
|
|
(define (fixed-point-of-transform g transform guess)
|
|
(fixed-point (transform g) guess))
|
|
|
|
(define (sqrt x)
|
|
(fixed-point-of-transform (lambda (y) (/ x y))
|
|
average-damp
|
|
1.0))
|
|
|
|
(define (sqrt x)
|
|
(fixed-point-of-transform (lambda (y) (- (square y) x))
|
|
newton-transform
|
|
1.0))
|
|
|
|
|
|
#+END_SRC
|
|
|
|
** Exercise 1.40
|
|
Define a procedure `cubic' that can be used together with the
|
|
`newtons-method' procedure in expressions of the form
|
|
|
|
#+begin_src scheme
|
|
(newtons-method (cubic a b c) 1)
|
|
#+end_src
|
|
|
|
to approximate zeros of the cubic x^3 + ax^2 + bx + c.
|
|
|
|
** Exercise 1.41
|
|
Define a procedure `double' that takes a procedure of one argument
|
|
as argument and returns a procedure that applies the original
|
|
procedure twice. For example, if `inc' is a procedure that adds 1
|
|
to its argument, then `(double inc)' should be a procedure that
|
|
adds 2. What value is returned by
|
|
|
|
#+begin_src scheme
|
|
(((double (double double)) inc) 5)
|
|
#+end_src
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
#+begin_src scheme :tangle yes
|
|
;; -------------------------------------------------------------------
|
|
;; Exercise 1.41
|
|
;; -------------------------------------------------------------------
|
|
|
|
(define (double f)
|
|
(lambda (x) (f (f x))))
|
|
|
|
(((double (double double)) inc) 5)
|
|
;Value: 21
|
|
|
|
#+end_src
|
|
** Exercise 1.42
|
|
Let f and g be two one-argument functions. The "composition" f
|
|
after g is defined to be the function x |-> f(g(x)). Define a
|
|
procedure `compose' that implements composition. For example, if
|
|
`inc' is a procedure that adds 1 to its argument,
|
|
|
|
#+begin_src scheme
|
|
((compose square inc) 6)
|
|
49
|
|
#+end_src
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
#+begin_src scheme :tangle yes
|
|
;; -------------------------------------------------------------------
|
|
;; Exercise 1.42
|
|
;; -------------------------------------------------------------------
|
|
|
|
(define (compose f g)
|
|
(lambda (x) (f (g x))))
|
|
|
|
#+end_src
|
|
** Exercise 1.43
|
|
If f is a numerical function and n is a positive
|
|
integer, then we can form the nth repeated application of f, which
|
|
is defined to be the function whose value at x is
|
|
f(f(...(f(x))...)). For example, if f is the function x |-> x +
|
|
1, then the nth repeated application of f is the function x |-> x
|
|
+ n. If f is the operation of squaring a number, then the nth
|
|
repeated application of f is the function that raises its argument
|
|
to the 2^nth power. Write a procedure that takes as inputs a
|
|
procedure that computes f and a positive integer n and returns the
|
|
procedure that computes the nth repeated application of f. Your
|
|
procedure should be able to be used as follows:
|
|
|
|
#+begin_src scheme
|
|
((repeated square 2) 5)
|
|
625
|
|
#+end_src
|
|
|
|
Hint: You may find it convenient to use `compose' from *Note
|
|
Exercise 1-42::.
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
#+begin_src scheme :tangle yes
|
|
;; -------------------------------------------------------------------
|
|
;; Exercise 1.43
|
|
;; -------------------------------------------------------------------
|
|
|
|
(define (repeated f times)
|
|
(if (= times 1)
|
|
(lambda (x) (f x))
|
|
(compose f (repeated f (- times 1)))))
|
|
#+end_src
|
|
** Exercise 1.44
|
|
The idea of "smoothing" a function is an important concept in
|
|
signal processing. If f is a function and dx is some small number,
|
|
then the smoothed version of f is the function whose value at a
|
|
point x is the average of f(x - dx), f(x), and f(x + dx). Write a
|
|
procedure `smooth' that takes as input a procedure that computes f
|
|
and returns a procedure that computes the smoothed f. It is
|
|
sometimes valuable to repeatedly smooth a function (that is, smooth
|
|
the smoothed function, and so on) to obtained the "n-fold smoothed
|
|
function". Show how to generate the n-fold smoothed function of
|
|
any given function using `smooth' and `repeated' from *Note
|
|
Exercise 1-43::.
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
#+begin_src scheme :tangle yes
|
|
;; -------------------------------------------------------------------
|
|
;; Exercise 1.44
|
|
;; -------------------------------------------------------------------
|
|
|
|
(define (smooth f)
|
|
(lambda (x) (/ (+ (f (- x dx))
|
|
(f x)
|
|
(f (+ x dx)))
|
|
3)))
|
|
|
|
(define (smooth-n f times)
|
|
((repeated smooth times) f))
|
|
#+end_src
|
|
** Exercise 1.45
|
|
We saw in section *Note 1-3-3:: that attempting to compute square
|
|
roots by naively finding a fixed point of y |-> x/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 y |-> x/y^2. Unfortunately, the process does not
|
|
work for fourth roots--a single average damp is not enough to make
|
|
a fixed-point search for y |-> x/y^3 converge. On the other hand,
|
|
if we average damp twice (i.e., use the average damp of the average
|
|
damp of y |-> x/y^3) 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 y |-> x/y^(n-1). Use this to implement a simple
|
|
procedure for computing nth roots using `fixed-point',
|
|
`average-damp', and the `repeated' procedure of *Note Exercise
|
|
1-43::. Assume that any arithmetic operations you need are
|
|
available as primitives.
|
|
|
|
** Exercise 1.46
|
|
Several of the numerical methods described in this chapter are
|
|
instances of an extremely general computational strategy known as
|
|
"iterative improvement". Iterative improvement says that, to
|
|
compute something, we start with an initial guess for the answer,
|
|
test if the guess is good enough, and otherwise improve the guess
|
|
and continue the process using the improved guess as the new guess.
|
|
Write a procedure `iterative-improve' that takes two procedures as
|
|
arguments: a method for telling whether a guess is good enough and
|
|
a method for improving a guess. `Iterative-improve' should return
|
|
as its value a procedure that takes a guess as argument and keeps
|
|
improving the guess until it is good enough. Rewrite the `sqrt'
|
|
procedure of section *Note 1-1-7:: and the `fixed-point' procedure
|
|
of section *Note 1-3-3:: in terms of `iterative-improve'.
|