;; CS101, Spring 2013 ;; Lecture #8 ;; ;; More recursion! ;; ; Mathematicians tell us that the number PI is approximated ; by sums of the form: ; ; 4 - 4/3 + 4/5 - 4/7 + 4/9 - ... (+/-) 4/n ; ; In particular, as the value of n gets larger, the value of ; the sum gets closer to PI. ; ; Notice that the terms in odd positions are added to the ; final value, and the terms in even positions are subtracted. ; What value of n corresponds to the first term? To the second ; term? How will n change for each recursive call? ; ; How will we distinguish the case where we add a term from ; the case in which we subtract a term? HINT: Use the ; remainder function to find the value returned from calcu- ; lating (remainder n 4). (remainder n 4) can only return ; 4 possible values for any positive value of n: 0, 1, 2, or 3. ; (remainder n 4) returns 0 or 2 only when n is even, which ; it won't be in this approximation. That leaves us with ; the cases in which (remainder n 4) returns either 1 or 3. ; ; What is returned by the function (remainder n 4) when we ; need to add a term in this equation? What is returned by ; (remainder n 4) when we need to subtract a term? ; Define a regular (suspended operation-style) recursive function ; to produce a sum to approximate pi, given n, an odd integer. ; ; CONTRACT: (approx-pi-n pos-odd-integer) -> number ; ; HEADER: (define approx-pi-n (lambda (n) ; ; PURPOSE: Output is equal to the sum ; ; 4 - 4/3 + 4/5 - 4/7 + ... (+/-)4/n ; ; which closely approximates PI for large enough n. ; ; ; ; PRE-FUNCTION TESTS: Need check-within instead of check-expect ; (check-within (approx-pi-n 5) 3.14 2) ; (check-within (approx-pi-n 111) pi .5) ; (check-within (approx-pi-n 1) 4.0 1) ; ; ; FUNCTION DEFINITION: ; (define approx-pi-n ; (lambda (n) ; ; ; ; POST-FUNCTION PRINTFS: ; (printf "(approx-pi-n 13) => ~a~%" (approx-pi-n 13)) ; (printf "(approx-pi-n 113) => ~a~%" (approx-pi-n 113)) ; (printf "(approx-pi-n 1113) => ~a~%" (approx-pi-n 1113)) ; ; (newline) ; (newline) ; How would we change the approx-pi-n function so that it would ; work for any odd or even positive integer? HINT: Add an extra ; recursive case to call approx-pi-n on n-1 if n is even. ; ------------------------------- ; ; Define a TAIL-RECURSIVE function, called APPROX-PI-N-ACC, that ; consumes the following inputs: ; N, a positive odd integer ; ACC, a positive integer (accumulator) ; ; When given appropriate values for the inputs, it ; should return as its output the result of evaluating ; the sum ; ; 4 - 4/3 + 4/5 - 4/7 + 4/9 - ... (+/-) 4/n ; ; ===> Your output values should get closer to PI as n ; increases. ; ;;; ========================================================== ; ; CONTRACT: (approx-pi-n-acc pos-integer number) -> number ; ; HEADER: (define approx-pi-n-acc (lambda (n acc) ; ; PURPOSE: If acc = 0 initially, then output is equal to the sum ; ; 4 - 4/3 + 4/5 - 4/7 + ... (+/-)4/n ; ; which closely approximates PI for large enough n. ; ; ; ; PRE-FUNCTION TESTS: Need check-within instead of check-expect ; (check-within (approx-pi-n-acc 5 0) 3.14 2) ; (check-within (approx-pi-n-acc 111 0) pi .5) ; (check-within (approx-pi-n-acc 2 0) 4.0 .001) ; ; ;;; FUNCTION: ; (define approx-pi-n-acc ; (lambda (n acc) ; ; ; ; ;;; ; ;;; POST-FUNCTION PRINTFS: ; (printf "(approx-pi-n-acc 5 0) -> ~a~%" (approx-pi-n-acc 5 0)) ; (printf "(approx-pi-n-acc 111 0) -> ~a~%" (approx-pi-n-acc 111 0)) ; (printf "(approx-pi-n-acc 2 0) -> ~a~%" (approx-pi-n-acc 2 0)) ; ; (newline) ; (newline) ; Define a wrapper function, approx-pi-n-acc-wrapper, that ; takes only one input, n. It should call approx-pi-n-acc ; with appropriately initialized input parameters. ; ; (pi-approx-n-acc-wrapper 1001) ===> 3.143588659585789 ; (pi-approx-n-acc-wrapper 10001) ===> 3.1417926135957908 ; ; CONTRACT: (approx-pi-n-acc-wrapper pos-integer) -> number ; ; HEADER: (define approx-pi-n-acc-wrapper (lambda (n) ...)) ; ; PURPOSE: Output is equal to the sum ; ; 4 - 4/3 + 4/5 - 4/7 + ... (+/-)4/n ; ; which closely approximates PI for large enough n. ; ; ; ; PRE-FUNCTION TESTS: Need check-within instead of check-expect ; (check-within (approx-pi-n-acc-wrapper 5) 3.14 2) ; (check-within (approx-pi-n-acc-wrapper 111) pi .5) ; (check-within (approx-pi-n-acc-wrapper 1) 4.0 .001) ; ; ; ;;;; FUNCTION: ; (define approx-pi-n-acc-wrapper ; (lambda (n) )) ; ; ; ;;; POST-FUNCTION PRINTFS: ; (printf "(approx-pi-n-acc-wrapper 50) -> ~a~%" (approx-pi-n-acc-wrapper 5)) ; (printf "(approx-pi-n-acc-wrapper 111) -> ~a~%" (approx-pi-n-acc-wrapper 111)) ; (printf "(approx-pi-n-acc-wrapper 1) -> ~a~%" (approx-pi-n-acc-wrapper 1)) ; ; (newline) ; (newline) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; The LOCAL special form: SPECIAL FORM 10 ; ; The local special form contains a "definition section" inside ; square braces. Within the square braces, you can write as ; many definitions as you want, for both constants and functions. ; ; (local ; [(define n1 ) ; (define n2 ) ; ... ; (define nk )] ; ) ; ; Where each can be any valid Racket expression, including ; a function definition. ; ; We will only use the local special form inside functions. ; You can view the local special form as setting up another ; local environment inside the local environment of the function ; that contains it. ; ; For example, the approx-pi function, given below, takes only ; one argument and produces the answer inside a local function. ; Instead of calling the approx-pi-n-acc, we'll write the equivalent ; of the accumulator function inside the wrapper (now called approx-pi). ; ; ; CONTRACT: (approx-pi pos-integer) -> number ; ; HEADER: (define approx-pi (lambda (n) ; ; PURPOSE: Output is equal to the sum ; ; 4 - 4/3 + 4/5 - 4/7 + ... (+/-)4/n ; ; which closely approximates PI for large enough n. ; ; ; PRE-FUNCTION TESTS: ; (check-within (approx-pi 5) 3.14 2) ; (check-within (approx-pi 111) pi .5) ; (check-within (approx-pi 1) 4.0 .001) ; ; ; FUNCTION DEFINITION: ; (define approx-pi ; (lambda (n) ; (local ; ; ;;; POST-FUNCTION PRINTFS: ; (printf "(approx-pi 50) -> ~a~%" (approx-pi 5)) ; (printf "(approx-pi 111) -> ~a~%" (approx-pi 111)) ; (printf "(approx-pi 1) -> ~a~%" (approx-pi 1)) ; ;; Example 2: Write a version of the copy function that uses a ;; local special form that defines an internal function to compute ;; the answer. ; ; ;; Contract: (copy string integer string) -> string ; ;; Header: (define copy (lambda (str n acc) ...)) ; ;; Purpose: produce string consisting of n copies of str. ; ;; Pre-function tests: ; (check-expect (copy "la" 4) "lalalala") ; (check-expect (copy "la" 1) "la") ; (check-expect (copy "do" 2) "dodo") ; (check-expect (copy "do" 0) "") ;