(* 15-212, Spring 2011 *) (* Michael Erdmann *) (* Code for Lecture 3: Recursion and Induction *) (************************************************************************) (* val power : (int * int) -> int power(n,k) ==> n^k, with 0^0 = 1 Invariant: k >= 0 Effects: none *) fun power (n:int, k:int) : int = if k = 0 then 1 else n * power (n, k-1); (* For the power function, checking the invariant might look like this: *) (* Check that k >= 0 *) fun power (n:int, k:int) : int = let fun p(k:int):int = if k = 0 then 1 else n*p(k-1) in if k < 0 then raise Domain else p(k) end; (* val even: int -> bool even(n) ==> true, if n is even, ==> false, if n is odd. Invariants: none Effects: none *) fun even (n:int) : bool = ((n mod 2) = 0); (* val square: int -> int square(n) ==> n^2 for integers n Invariants: none Effects: none *) fun square (n:int) : int = n * n; (* val power2 : (int * int) -> int power2(n,k) ==> n^k, with 0^0 = 1 Invariant: k >= 0 Effects: none power2 computes n^k using O(log(k)) multiplies. *) fun power2 (n:int, k:int) : int = if k = 0 then 1 else if even(k) then square(power2(n, k div 2)) else n * power2(n, k-1); (* Patterns *) val (a, (b, c)) : int * (int * real) = (3, (4, 5.2)); val (a, d) : int * (int * real) = (3, (4, 5.2)); (* Recursion and Induction *) (* val fib: int -> int fib(n) ==> f_n, the nth Fibonacci number. Invariant: n >= 0. Effects: none This definition requires fib(n) calls to compute fib(n). *) fun fib(0:int):int = 1 | fib(1:int):int = 1 | fib(n:int):int = fib(n-1) + fib(n-2); (* val fibb: int -> int*int fibb(n) ==> (f_n, f_{n-1}), the nth and {n-1}st Fibonacci numbers, where we define f_{-1} = 0. Invariant: n >= 0. Effects: none This definition requires only n calls to compute fibb(n). *) fun fibb (0:int):int*int = (1, 0) | fibb (n:int):int*int = let val (f_1, f_2) : int*int = fibb (n-1) in (f_1 + f_2, f_1) end; (* val fibonacci: int -> int fibonacci(n) ==> f_n, the nth Fibonacci number. Invariants: n >= 0. Effects: none This definition uses fibb. *) (* This is slightly ugly, but ok for one line. *) fun fibonacci(n:int):int = #1(fibb(n)); (* The following definition relies on reals, which is dangerous because of rounding errors. Do not rely on this function! NOTE: this solution comes from solving the recurrence explicitly. *) fun fib3 (n:int) : int = Real.round ((Math.pow((1.0+Math.sqrt(5.0))/2.0, real(n+1)) - Math.pow((1.0-Math.sqrt(5.0))/2.0, real(n+1))) / Math.sqrt(5.0)); (************************************************************************)