mirror of
https://github.com/correl/sicp.git
synced 2024-11-23 11:09:57 +00:00
1.3.3 and 1.3.4 exercises
This commit is contained in:
parent
54cfe3ef33
commit
ef7ca0372e
1 changed files with 385 additions and 0 deletions
385
1-3.org
385
1-3.org
|
@ -269,4 +269,389 @@ layout: org
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
* Procedures as General Methods
|
* 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
|
* 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
|
||||||
|
|
||||||
|
** 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
|
||||||
|
|
||||||
|
** 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::.
|
||||||
|
|
||||||
|
** 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::.
|
||||||
|
|
||||||
|
** 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'.
|
||||||
|
|
Loading…
Reference in a new issue