[SICP 1.3.3] Exercise 1.37-1.39 Memo
5-18-2014
Exercise 1.37(a)- define k-term finite continued fraction.
Linear recursive version:
(define (cont-frac n d k) (define (cont-frac-iter i) (if (= i k) (/ (n i) (d i)) (/ (n i) (+ (d i) (cont-frac-iter (+ i 1.0))))) ) (cont-frac-iter 1) )
Then how can we check if the number of k is enough for the calculation in the accuracy of 0.0001? We may be able to check it manually, but creating a checking function seems to be better for me.
(define (check-accuracy) (define (iter k) (if (< (abs (- (calc-ratio k) (/ 1 1.6180339887)) ) 0.0001) k (iter (+ k 1)) ) ) (iter 1) )
And we get 10 iterations to get the accuracy in 0.0001.
In this case, the function passes calc-ratio method without using arguments. You can build an abstraction for checking arbitrary accuracy of arbitrary function if you prefer.
(define (check-accuracy accuracy f target) (define (iter k) (if (< (abs (- (f k) target) ) accuracy) k (iter (+ k 1)) ) ) (iter 1) )
Exercise 1.37(b) Write linear-iterative version of cont-frac function ( if you’ve created the linear-iterative one in the Exercise 1.37(a), then create linear-recursive version )
The linear-recursive version processes the calculation from 1 to n, but we need to change this process from n to 1 for creating the linear-iterative one, because if we try to start from 1 and make it increment the number, the requirement of the result of (i + 1)th process occurs to determine the result of i-th process. Then the function will be as follows:
(define (cont-frac-linear-iterative n d k) (define (cont-frac-iter numerator i) (cond ((= i 1) numerator) ((= i k) (cont-frac-iter (/ (n (- i 1.0)) (+ (/ (n i) (d i)) (d (- i 1.0)))) (- i 1.0))) (else (cont-frac-iter (/ (n (- i 1.0)) (+ numerator (d (- i 1.0)))) (- i 1.0))) ) ) (cont-frac-iter 0 k) )
Let’s check two versions of cont-frac function.
(define (calc-ratio k) (cont-frac (lambda (x) 1.0) (lambda (x) 1.0) k)) (define (calc-ratio2 k) (cont-frac-linear-iterative (lambda (x) 1.0) (lambda (x) 1.0) k)) (calc-ratio 100) ; 0.6180339887498948 (calc-ratio2 100) ; 0.6180339887498948 (calc-ratio 10000000) ; used up the memory (calc-ratio2 10000000) ; 0.6180339887498948
Exercise 1.38 – define the natual logarithm e.
We finally get the expression of the 1, 2, 1, 1, 4, 1, 1, 6, 1, 1, 8, … as follows:
(define (e) (+ 2 (cont-frac-linear-iterative (lambda (a) 1.0) (lambda (a) (if (< (remainder a 3) 2) 1.0 (* (/ 2.0 3.0) (+ a 1)))) 1000 )) )
The output is:
(e) ; 2.7182818284590455
(if (< (remainder a 3) 2) 1.0 [calculation] ) means that the element that (= (remainder a 3) 0) or (= (remainder a 3) 1) will be 1.0.
To get the meaning of [calculation] ( that is, (* (/ 2.0 3.0) (+ a 1)) ), we need some conversion of numbers.
—
n = 2, 5, 8, 11, 14
m = 1, 2, 3, 4, 5
a(m) = 2, 4, 6, 8, 10 = (* 2 m)
—
then m = (* (/ 1 3 ) ( n + 1 ))
so a(n) = (* 2 m) = (* 2 (* (/ 1 3 ) ( n + 1 ))) = (* (/ 2 3 ) ( n + 1 ))
Exercise 1.39 - Define a procedure (tan-cf x k) that computes an approximation to the tangent
function based on Lambert’s formula.
Note that the operand of the calculation in numerators is minus.
(define (tan-cf x k) (cont-frac-linear-iterative (lambda (a) (if (= a 1) x (- (* x x)))) (lambda (a) (- (* 2 a) 1)) k ) )
The output is:
(tan-cf 1.0 1000) ; 1.557407724654902