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
|
||||
|
||||
* 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
|
||||
|
||||
** 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