* 1.2 Procedures and the Processes they Generate "To become experts, we must learn to visualize the processes generated by various types of procedures" - local evolution :: pattern defined by a procedure about how each stage of the process is built off each other We make statements about the global behavior whose local evolution has been specified by a procedure. we will examine common process "shapes" ** 1.2.1 Linear Recursion & Iteration there are numerous ways to calculate 6! linear recursive approach: #+BEGIN_SRC scheme (define (factorial n) (if (= n 1) 1 (* n (factorial (- n 1))))) (factorial 6) #+END_SRC #+RESULTS: : 720 linear iterative approach: #+BEGIN_SRC scheme (define (factorial n) (fact-iter 1 1 n)) (define (fact-iter product counter max-count) (if (> counter max-count) product (fact-iter (* counter product) (+ counter 1) max-count))) (factorial 6) #+END_SRC #+RESULTS: : 720 here are the shapes of the two approaches, using the substitution model: #+BEGIN_SRC ;; linear recursive (factorial 6) (* 6 (factorial 5)) (* 6 (* 5 (factorial 4))) (* 6 (* 5 (* 4 (factorial 3)))) (* 6 (* 5 (* 4 (* 3 (factorial 2))))) (* 6 (* 5 (* 4 (* 3 (* 2 (factorial 1)))))) (* 6 (* 5 (* 4 (* 3 (* 2 1))))) (* 6 (* 5 (* 4 (* 3 2)))) (* 6 (* 5 (* 4 6))) (* 6 (* 5 24)) (* 6 120) 720 ;; linear iterative (factorial 6) (fact-iter 1 1 6) (fact-iter 1 2 6) (fact-iter 2 3 6) (fact-iter 6 4 6) (fact-iter 24 5 6) (fact-iter 120 6 6) (fact-iter 720 7 6) 720 #+END_SRC - deferred operations :: the functions "stacking up" in the l.r. model above - recursive process :: characterized by a chain of deferred operations - iterative process :: state can be summarized by fixed number of state variables - linear recursive process :: a recursion where the chain of deferred operations grows linearly with n - linear iterative process :: an iteration where the number of steps grows linearly with n the iterative approach maintains its own state, explicitly. when using recursion, state is hidden. !! don't confuse a recursive process with a recursive procedure - tail recursion :: a language implementation that executes iterative processes in constant space, even if described by a recursive procedure languages such as c consume memory with each procedure call, even if the described process is iterative. this is not tail recursive. the IEEE standard for scheme requires that implementations be tail recursive. ** 1.2.2 Tree Recursion -- > 0 if n = 0 / fib(n) ---- > 1 if n = 1 \ -- > fib(n-1)+fib(n-2) else #+BEGIN_SRC scheme (define (fib n) (cond ((= n 0) 0) ((= n 1) 1) (else (+ (fib (- n 1)) (fib (- n 2)))))) (fib 7) #+END_SRC #+RESULTS: : 13 #+BEGIN_SRC scheme (define (fib n) (fib-iter 1 0 n)) (define (fib-iter a b count) (if (= count 0) b (fib-iter (+ a b) a (- count 1)))) (fib 8) #+END_SRC #+RESULTS: : 21 the first impl traverses a tree. useful, but number of steps is very high, even with small inputs. the second impl is blazing fast by comparison, as a linear iter. ** 1.2.3 Orders of Growth computational resources n is a param that measures the size of a problem R(n) is the amt of resources that n requires ϴ(f(n)) is R(n)'s order of growth growth can be constant, linear, exponential etc. "big o" shit the following algorithms in §1.2 will be logarithmic in growth ** 1.2.4 Exponentiation how to compute an exponent? for b base n positive integer exponent b^n = b * b^n-1 b^0 = 1 linear recursive process, ϴ(n) steps, ϴ(n) space: #+BEGIN_SRC scheme (define (expt b n) (if (= n 0) 1 (* b (expt b (- n 1))))) (expt 9 9) #+END_SRC #+RESULTS: : 387420489 linear iterative process, ϴ(n) steps, ϴ(1) space: #+BEGIN_SRC scheme (define (expt b n) (expt-iter b n 1)) (define (expt-iter b counter product) (if (= counter 0) product (expt-iter b (- counter 1) (* b product)))) (expt 35 17) #+END_SRC #+RESULTS: : 1.7748299712158738e+26 fast as hell method: #+BEGIN_SRC scheme (define (fast-expt b n) (cond ((= n 0) 1) ((even? n) (square (fast-expt b (/ n 2)))) (else (* b (fast-expt b (- n 1)))))) (define (even? n) (= (remainder n 2) 0)) (fast-expt 5 5) #+END_SRC #+RESULTS: ** 1.2.5 Greatest Common Divisors a gcd is the largest int that can divide 2 ints with no remainder given ints a, b; r is the remainder of a/b gcd(a, b)==gcd(b, r) # br! euclid's algo (book 2 proposition 2): gcd(206,40) = gcd(40, 6) = gcd(6, 4) = gcd(4, 2) = gcd(2, 0) = 2 #+BEGIN_SRC scheme (define (gcd a b) (if (= b 0) a (gcd b (remainder a b)))) (gcd 81 18) #+END_SRC #+RESULTS: : 9 !! euclid's algo has logorithmic growth - Lamé's theorem :: a euclid algo taking k steps to solve a gcd, the smaller of the two numbers is greater or equal to the kth fibonacci number