CS153, Class 8: Numeric Recursion
Overview:
* Short discussion
* Lab
* Reflection
Administrivia:
* Questions on homework 1?
* Yes, you can do work during my other classes.
* Did anyone solve the efficient exponentiation problem?
* Read "Local bindings" for Monday.
----------------------------------------
(define expt-one
(lambda (base power)
(if (zero? power)
1
(* base (expt-one base (- power 1))))))
Approximate running time:
Some fixed multiple of "power" steps
(define square (lambda (x) (* x x)))
(define expt-two
(lambda (base power)
(cond
((zero? power) 1)
((even? power) (square (expt-two base (quotient power 2))))
(else (* base (expt-two base (- power 1)))))))
Approximate running time:
Some multiple of "log base 2 of power" steps
TRY AGAIN!
----------------------------------------
To solve a big problem:
(1) Make a simpler but similar problem
(2) Assume you can solve the simpler problem
(3) Use the solution to the simpler problem to solve
the bigger problem.
The "magic": Once you've done this, use the same technique
to solve the simpler problem.
Instead of going from simple to hard, you go from hard
down to simple and then back up again.
Key design techniques:
* Simplify
+ With lists: Typically: take the cdr
+ With numbers: Typically: subtract 1
* Determine when to stop
+ With lists: Typically: when empty
Sometimes: When one element
+ With numbers: Typically: When 0 or 1
* Combine
+ Depends on the desired output type
+ Generating lists: cons, append
+ Generating numbers: add, multiply, etc.
----------------------------------------
REFLECTION
* Whoops: Sam forgot to tell you to read "Local Bindings"
for Monday.
: Sometimes it's a good idea to save your partially-incorrect
solutions.
* Be careful on base cases and special cases
+ (count-down 0)
+ (iota 0)
+ (fill-list 'a -1)
* Preconditions are your friend.
+ If someone doesn't meet a precondition, what should you do?
+ Careful programmers: Test for the preconditions and report
an error.
+ Programmers worried about efficiency: "If you test for
conditions that are supposed to hold, you're slowing down
the program."
+ Smart programmers: Design two versions of each procedure,
one safe and one unsafe.
* Why doesn't Sam like the following procedure?
(define one?
(lambda (val)
(if (= val 1) #t #f)))
(define one?
(lambda (val)
(= val 1)))
* What, if anything, is wrong with the following?
(define iota
(lambda (val)
(if (zero? val)
null
(append (iota (- val 1)) (list (- val 1))))))
EFFICIENCY:
For iota of five, we need to compute iota of 4, and then
do a four or five -step append operation
3 or 4 step append operation for iota of 3
...
For (iota n), what's the total cost of appending?
1 + 2 + 3 + .... + n
(define iota
(lambda (val)
(if (zero? val)
null
(reverse (cons (- val 1) (reverse (iota (- val 1))))))))
* What would be better?
(define iota
(lambda (val)
(reverse (count-down (- val 1)))))
* "Decimal number" has two distinct meanings:
+ "Base 10 number" (what we mean)
+ "Stuff after the decimal point" (what some seem to hear)
* Here's a bad definition of closest-to-zero
(define closest-to-zero
(lambda (vals)
(cond
((null? (cdr vals)) (car vals))
((< (abs (car vals)) (abs (closest-to-zero (cdr vals))))
(car vals))
(else (closest-to-zero (cdr vals))))))
* Here's a better one
(define closer-to-zero
(lambda (a b)
(if (< (abs a) (abs b)) a b)))
(define closest-to-zero
(lambda (vals)
(if (null? (cdr vals)) (car vals)
(closer-to-zero (car vals) (closest-to-zero (cdr vals))))))