
I'm working on transcribing my notes from the next SICP lecture, so I'll have a real post up soon. Happy Halloween everyone!
"The time has come," the Walrus said, "To talk of many things..."
(define (new-if predicate then-clause else-clause)
(cond (predicate then-clause)
(else else-clause)))
The new-if procedure seems to work with simple conditional statements on the command line, but if you then define the sqrt-iter procedure in terms of new-if, you notice something peculiar. The sqrt-iter procedure defined in terms of new-if never finishes executing.To evaluate an if expression, the interpreter starts by evaluating the "predicate" part of the expression. If the "predicate" evaluates to a true value, the interpreter then evaluates the "consequent" and returns its value. Otherwise it evaluates the "alternative" and returns its value.
(sqrt 0.001)
and you should get a wrong answer. Instead of 0.0316227766 as you might expect, our sqrt procedure gives an answer of 0.0412454261. The problem is that as we refine our guess, we stop as soon as the square of our guess is within 0.001 of x. Squaring 0.0412454261we get 0.00170118517, which we can see is within our tolerance of 0.001.(sqrt 9999999999998)
will never return. (I'm using PLT Scheme with the "Module" language selected for the exercises in this section. You may have different results.)(define (square x)
(* x x))
(define (average x y)
(/ (+ x y)
2))
(define (good-enough? guess previous-guess)
(< (abs (- guess previous-guess))
0.001))
(define (improve guess x)
(average guess
(/ x guess)))
(define (sqrt-iter guess previous-guess x)
(if (good-enough? guess previous-guess)
guess
(sqrt-iter (improve guess x)
guess
x)))
(define (sqrt x)
(sqrt-iter 1.0 0 x))
Note that the good-enough-procedure no longer takes x as an input parameter, but instead decides whether or not a guess is good enough based on the change from the previous guess. This change also called for a change to the sqrt-iter procedure, which must now keep track of the previous guess. Finally, note that when I first call the sqrt-iter procedure in sqrt, I pass in values of 1.0 and 0 for the initial guess and the previous guess. This ensures that the difference will be greater than our tolerance for at least one recursive call of sqrt-iter.(define (improve guess)
(/ (+ (/ x
(square guess))
(* 2 guess))
3))
Putting it all together (starting from the improved version of sqrt that we wrote in the previous exercise) we get:(define (square x)
(* x x))
(define (good-enough? guess previous-guess)
(< (abs (- guess previous-guess))
0.001))
(define (improve guess x)
(/ (+ (/ x
(square guess))
(* 2 guess))
3))
(define (cbrt-iter guess previous-guess x)
(if (good-enough? guess previous-guess)
guess
(cbrt-iter (improve guess x)
guess
x)))
(define (cbrt x)
(cbrt-iter 1.0 0 x))
We can test it out with the values that gave us problems before, with the following results:> (sqrt 0.001)
0.03162278245070105
> (sqrt 99999999999998)
9999999.9999999
(/ (+ 5 4 (- 2 (- 3 (+ 6 (/ 4 5)))))
(* 3 (- 6 2) (- 2 7)))
You can check with a Scheme interpreter to verify that this expression also evaluates to -37/150.The sum-of-highest-squares works by adding the square of the maximum of x and y (not the lowest of the three) and the square of the maximum of the remaining two (the minimum of x and y, which will be whichever value was left over from the first step), and z.(define (square x)
(* x x))
(define (max x y)
(if (> x y) x y))(define (min x y)
(if (< x y) x y))
(define (sum-of-highest-squares x y z)
(+ (square (max x y))
(square (max (min x y) z))))
(define (a-plus-abs-b a b)
((if (> b 0) + -) a b))
Before the entire expression can be evaluated, the compound if expression must be evaluated so the interpreter can determine whether the + or - operator should be applied to the two operands a and b. If b i greater than 0, the + operator is applied, adding a positive value to a. Otherwise, the - operator is applied, subtracting a negative value. In either case, the result is the same. The absolute value of b is added to a.(define (p) (p))
(define (test x y)
(if (= x 0)
0
y))
The first procedure simply makes a recursive call to itself. If you evaluate (p) directly in the Scheme interpreter, it will never return because each recursive call makes another recursive call with no base case defined. The test procedure is used to determine the evaluation order of the interpreter by running it with the recursive procedure as its second argument.(test 0 (p))
has one operand and two arguments, all of which will be evaluated. The operand test will evaluate to the body of its procedure, the symbol 0 will evaluate to its value, and the operand (p) will evaluate to a recursive call to itself, which will never stop recursing.Computer Science is no more about computers than astronomy is about telescopes.
(+ 3 17.4 5)
(+ 3 (* 2 4) 7)
(* (+ 2 (* 4 6))
(+ 3 5 7))
is represented by the following tree diagram (from section 1.1.3 of the course text, Evaluating Combinations)(define (square x)
(* x x))
(square 10)
(define square (lambda (x)
(* x x)))
Technically, the first syntax we looked at is the alternative, and this syntax is the more "correct" one. In Lisp, the lambda keyword is used to define a function. If you're giving a function a name, the alternative syntax we looked at first is a shorter way to do the same thing. Later on in the course we'll be looking at situations where we might want to create a function without explicitly giving it a name. We'll come back to the lambda operator then. For now, we'll use the short syntax for defining procedures.(define (average x y)
(/ (+ x y) 2))
The average of x and y is computed by dividing the sum of x and y by 2.(define (abs x)
(cond ((< x 0) -x))
((= x 0) 0)
((> x 0) x)))
Refer to section 1.1.6 of the text, Conditional Expressions and Predicates for a more complete discussion of conditionals, including the most common logical composition operators (and, or , and not) which are not covered in the lecture.(define (try guess x)
(if (good-enough? guess x)
guess
(try (improve guess x) x)))
(define (sqrt x) (try 1 x))
(define (improve guess x)
(average guess (/ x guess)))
(define (good-enough? guess x)
(< (abs (- (square guess) x))
0.001))
Procedures | Data | |
---|---|---|
Primitive Elements | + - * / = | 23 1.738 |
Means of Combination | ( ) cond if | |
Means of Abstraction | define |