Solution to SICP Exercise 1.9

Structure and Interpretation of Computer Programs

Solution to Exercise 1.9:

The first procedure follows a recursive process:

(+ 4 5)
(inc (+ (dec 4) 5))
(inc (+ 3 5))
(inc (inc (+ (dec 3) 5)))
(inc (inc (+ 2 5)))
(inc (inc (inc (+ (dec 2) 5))))
(inc (inc (inc (+ 1 5))))
(inc (inc (inc (inc (+ (dec 1) 5)))))
(inc (inc (inc (inc (+ 0 5)))))
(inc (inc (inc (inc 5))))
(inc (inc (inc 6)))
(inc (inc 7))
(inc 8)
9

The second follows an iterative one:

(+ 4 5)
(+ (dec 4) (inc 5))
(+ 3 6)
(+ (dec 3) (inc 6))
(+ 2 7)
(+ (dec 2) (inc 7))
(+ 1 8)
(+ (dec 1) (inc 8))
(+ 0 9)
9

Solution to SICP Exercise 1.8

Structure and Interpretation of Computer Programs

Solution to Exercise 1.8:

(define (square x)
(* x x))

(define (cube x)
(* x x x))

(define (cbrt-iter guess prev-guess x)
(if (good-enough? guess prev-guess)
guess
(cbrt-iter (improve guess x)
guess
x)))

(define (improve guess x)
(/ (+ (/ x (square guess))
(* 2 guess))
3))

(define (good-enough? guess prev-guess)
(< (/ (abs (- guess prev-guess))
guess)
0.001))

(define (cbrt x)
(cbrt-iter 1.0 0.0 x))

This solution uses the guess evaluation strategy of Exercise 1.7.

It seems to give reasonable results:

> (cbrt 8)
2.000000000012062
> (cbrt 27)
3.0000005410641766
> (cbrt 64)
4.000000000076121

Solution to SICP Exercise 1.7

Structure and Interpretation of Computer Programs

Solution to Exercise 1.7:

The results for small values become very inaccurate. For example, the root of the square of 0.001, which we might expect to be itself is found to be off by a factor of ~31.3 times.

> (sqrt (square 0.001))
0.031260655525445276

As the values grow larger, the precision of the guess comes into play. Eventually the computer becomes unable to represent the guess to a precision of 0.001. In such cases, the program can endlessly alternate between two guesses that are more than 0.001 away from the true square root. On my x86 machine with DrScheme, this can be seen with the following expression

> (sqrt 1e13)

Here is an implementation of good-enough/ that follows the alternative strategy given in the exercise

(define (good-enough? guess prev-guess)
(< (/ (abs (- guess prev-guess))
guess)
0.001))

The x parameter is replaced by prev-guess, which necessitates a change to sqrt-iter and sqrt, as shown here:

(define (sqrt-iter guess prev-guess x)
(if (good-enough? guess prev-guess)
guess
(sqrt-iter (improve guess x)
guess
x)))

(define (sqrt x)
(sqrt-iter 1.0 0.0 x))

I’ve used an initial prev-guess of zero, which ensures that the initial guess of one is never good enough, thus forcing at least one iteration of the algorithm.

This implementation performs much better on the two troublesome examples given above:

> (sqrt (square 0.001))
0.0010000001533016628
> (sqrt 1e13)
3162277.6640104805

Support Mandy in the Weekend to End Breast Cancer

The Weekend to End Breast CancerIn September, Mandy will be walking in The Weekend to End Breast Cancer, a two-day, 60km walk to raise money for the Princess Margaret Hospital Foundation, Canada’s largest institution devoted to cancer research and treatment. She writes:

I will be walking for my stepmother, Linda, who is a survivor and I will be walking for and with my sister, Lauren, who I hope will never have to go through what her mother went through. Please help make this possible.

You can donate online through Mandy’s donation page.

Solution to SICP Exercise 1.5

Structure and Interpretation of Computer Programs

Solution to Exercise 1.5:

With applicative-order evaluation, the expression that Ben entered for evaluation will fail to terminate. The reason for this has to do with expression (p) evaluating to itself. When evaluating with applicative order, every combination within an expression is evaluated before the expression itself. The (p) combination never finishes evaluating because it keeps evaluating to itself.

With normal-order evaluation, the expression will be evaluated to 0. The reason is that the (p) combination is passed to test unevaluated. According to normal-order evaluation rules, it isn’t evaluated by the interpreter until its value is needed. The condition of the if expression in test is satisfied (because the expression (= 0 0) evaluates to #t, so the test procedure evaluates to 0. There is never any need to evaluate (p).

Solution to SICP Exercise 1.1

Structure and Interpretation of Computer Programs

This morning I began my third attempt at reading the programming classic Structure and Interpretation of Computer Programs, otherwise known as SICP. My earlier attempts stalled for various reasons, but this time I hope to get through the entire book. As an incentive to finish, I’m publicly promising to post my solutions to all the exercises in the book on this blog, starting with Exercise 1.1:
>10
10

>(+ 5 3 4)
12

>(- 9 1)
8

>(/ 6 2)
3

>(+ (* 2 4) (- 4 6))
6

>(define a 3)

>(define b (+ a 1))

>(+ a b (* a b))
19

>(= a b)
#f

>(if (and (> b a) ((cond ((= a 4) 6)
((= b 4) (+ 6 7 a))
(else 25))
16

>(+ 2 (if (> b a) b a))
6

>(* (cond ((> a b) a)
((< a b) b)
(else -1))
(+ a 1))
16