From bc04031dffe7dbc1a533e4d077c8b6c9bdde4f43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petar=20Kapri=C5=A1?= Date: Tue, 4 Feb 2025 21:35:51 +0100 Subject: [PATCH] Add solutions to exercises from section 1.3 --- ex-1.29.scm | 22 +++++++++++++++ ex-1.30.scm | 8 ++++++ ex-1.31.scm | 25 +++++++++++++++++ ex-1.32.scm | 13 +++++++++ ex-1.33.scm | 39 ++++++++++++++++++++++++++ ex-1.34.txt | 4 +++ ex-1.35.scm | 24 ++++++++++++++++ ex-1.36.scm | 28 ++++++++++++++++++ ex-1.37.scm | 11 ++++++++ ex-1.38.scm | 16 +++++++++++ ex-1.39.scm | 15 ++++++++++ ex-1.40.scm | 7 +++++ ex-1.41.scm | 12 ++++++++ ex-1.42.scm | 4 +++ ex-1.43.scm | 11 ++++++++ ex-1.44.scm | 9 ++++++ ex-1.45.scm | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++ ex-1.46.scm | 24 ++++++++++++++++ 18 files changed, 353 insertions(+) create mode 100644 ex-1.29.scm create mode 100644 ex-1.30.scm create mode 100644 ex-1.31.scm create mode 100644 ex-1.32.scm create mode 100644 ex-1.33.scm create mode 100644 ex-1.34.txt create mode 100644 ex-1.35.scm create mode 100644 ex-1.36.scm create mode 100644 ex-1.37.scm create mode 100644 ex-1.38.scm create mode 100644 ex-1.39.scm create mode 100644 ex-1.40.scm create mode 100644 ex-1.41.scm create mode 100644 ex-1.42.scm create mode 100644 ex-1.43.scm create mode 100644 ex-1.44.scm create mode 100644 ex-1.45.scm create mode 100644 ex-1.46.scm diff --git a/ex-1.29.scm b/ex-1.29.scm new file mode 100644 index 0000000..16dbb7c --- /dev/null +++ b/ex-1.29.scm @@ -0,0 +1,22 @@ +#lang sicp +; (define (cube x) (* x x x)) + +(define (sum term a next b) + (if (> a b) + 0 + (+ (term a) + (sum term (next a) next b)))) + +(define (inc x) (+ 1 x)) + +(define (simpson f a b n) + (define h (/ (- b a) n)) + (define (add-h x) (+ x h)) + (define (term i) + (cond ((= i 0) (f a)) + ((= i n) (f b)) + ((even? i) (* 2 (f (+ a (* i h))))) + (else (* 4 (f (+ a (* i h))))))) + (* h + (/ 1.0 3) + (sum term 0 inc n))) diff --git a/ex-1.30.scm b/ex-1.30.scm new file mode 100644 index 0000000..8ff401e --- /dev/null +++ b/ex-1.30.scm @@ -0,0 +1,8 @@ +#lang sicp + +(define (sum term a next b) + (define (iter a result) + (if (> a b) + result + (iter (next a) (+ result (term a))))) + (iter a 0)) diff --git a/ex-1.31.scm b/ex-1.31.scm new file mode 100644 index 0000000..c1dc8b8 --- /dev/null +++ b/ex-1.31.scm @@ -0,0 +1,25 @@ +#lang sicp + +(define (product term a next b) + (define (iter a result) + (if (> a b) + result + (iter (next a) (* result (term a))))) + (iter a 1)) + +(define (pi-prod n) + (define (pi-term i) + (if (even? i) + (/ (+ i 2) (+ i 1)) + (/ (+ i 1) (+ i 2)))) + (product pi-term 1 inc n)) + +;(define (inc x) (+ x 1)) + +(define (factorial n) + (product identity 1 inc n)) + +(define (product-rec term a next b) + (if (> a b) + 1 + (* (term a) (product-rec term (next a) next b)))) diff --git a/ex-1.32.scm b/ex-1.32.scm new file mode 100644 index 0000000..a23718f --- /dev/null +++ b/ex-1.32.scm @@ -0,0 +1,13 @@ +#lang sicp + +(define (accumulate combiner null-value term a next b) + (define (iter a result) + (if (> a b) + result + (iter (next a) (combiner result (term a))))) + (iter a null-value)) + +(define (sum term a next b) + (accumulate + 0 term a next b)) +(define (product term a next b) + (accumulate * 1 term a next b)) diff --git a/ex-1.33.scm b/ex-1.33.scm new file mode 100644 index 0000000..13007dc --- /dev/null +++ b/ex-1.33.scm @@ -0,0 +1,39 @@ +#lang sicp + +(define (filtered-accumulate combiner + null-value + term + a + next + b + pred?) + (define (iter a result) + (cond ((> a b) result) + ((pred? a) (iter (next a) + (combiner result (term a)))) + (else (iter (next a) result)))) + (iter a null-value)) + +(define (square x) (* x x)) + +(define (smallest-divisor n) (find-divisor n 2)) +(define (find-divisor n test-divisor) + (cond ((> (square test-divisor) n) n) + ((divides? test-divisor n) test-divisor) + (else (find-divisor n (+ test-divisor 1))))) +(define (divides? a b) (= (remainder b a) 0)) +(define (prime? n) + (= n (smallest-divisor n))) + +(define (prime-square-sum a b) + (filtered-accumulate + 0 square a inc b prime?)) + +(define (gcd a b) + (if (= b 0) + a + (gcd b (remainder a b)))) + +(define (rel-prime-product n) + (define (rel-prime-n? i) + (= (gcd i n) 1)) + (filtered-accumulate * 1 identity 1 inc n rel-prime-n?)) diff --git a/ex-1.34.txt b/ex-1.34.txt new file mode 100644 index 0000000..3085756 --- /dev/null +++ b/ex-1.34.txt @@ -0,0 +1,4 @@ +(f f) +(f 2) +(2 2) +Error: 2 is not a procedure diff --git a/ex-1.35.scm b/ex-1.35.scm new file mode 100644 index 0000000..ef7e6c3 --- /dev/null +++ b/ex-1.35.scm @@ -0,0 +1,24 @@ +#lang sicp + +(define tolerance 0.00001) + +(define (fixed-point f first-guess) + (define (close-enough? v1 v2) + (< (abs (- v1 v2)) tolerance)) + (define (try guess) + (let ((next (f guess))) + (if (close-enough? guess next) + next + (try next)))) + (try first-guess)) + +; below is phi +; +; proof: f(x) = 1 + 1/x +; f(phi) = 1 + 1/((1+sqrt(5))/2) = 1 + 2/(1+sqrt(5)) = +; (1+sqrt(5))/(1+sqrt(5)) + 2/(1+sqrt(5)) = +; ( 3+sqrt(5) ) / (1+sqrt(5)) (multiply and divide by (1-sqrt(5))) +; you get: (1+sqrt(5))/2 qed +; +(define phi (fixed-point (lambda (x) (+ 1 (/ 1 x))) 2.0)) +(define solution (lambda (x) (+ 1 (/ 1 x)))) diff --git a/ex-1.36.scm b/ex-1.36.scm new file mode 100644 index 0000000..747435b --- /dev/null +++ b/ex-1.36.scm @@ -0,0 +1,28 @@ +#lang sicp +(define tolerance 0.00001) +(define (fixed-point f guess) + (define new-guess (f guess)) + (cond ((< (abs (- guess new-guess)) tolerance) + (display new-guess) + (newline) + (f guess)) + (else + (display new-guess) + (newline) + (fixed-point f new-guess)))) + +; 34 steps without damping +(define solution (fixed-point + (lambda (x) (/ (log 1000) + (log x))) + 2.0)) +(newline) +(newline) +(newline) +; 9 steps with average damping +(define solution-damped + (fixed-point (lambda (x) (/ (+ x + (/ (log 1000) + (log x))) + 2.0)) + 2.0)) diff --git a/ex-1.37.scm b/ex-1.37.scm new file mode 100644 index 0000000..e8c1b9e --- /dev/null +++ b/ex-1.37.scm @@ -0,0 +1,11 @@ +#lang sicp + +(define (cont-frac n d k) + (define (cf-acc n d k i) + (if (= k i) + (/ (n i) (d i)) + (/ (n i) (+ (d i) (cf-acc n d k (+ i 1)))))) + (cf-acc n d k 0)) + +; it takes exactly k = 10, for 1/phi to be estimated accurately up to the +; 4th decimal diff --git a/ex-1.38.scm b/ex-1.38.scm new file mode 100644 index 0000000..9ac5949 --- /dev/null +++ b/ex-1.38.scm @@ -0,0 +1,16 @@ +#lang sicp + +(define (cont-frac n d k) + (define (cf-acc n d k i) + (if (= k i) + (/ (n i) (d i)) + (/ (n i) (+ (d i) (cf-acc n d k (+ i 1)))))) + (cf-acc n d k 0)) + +(define (e k) + (+ 2.0 (cont-frac (lambda (i) 1.0) + (lambda (i) + (if (= (remainder i 3) 1) + (* 2.0 (/ (+ i 2) 3)) + 1.0)) + k))) diff --git a/ex-1.39.scm b/ex-1.39.scm new file mode 100644 index 0000000..9b8bfa5 --- /dev/null +++ b/ex-1.39.scm @@ -0,0 +1,15 @@ +#lang sicp + +(define (cont-frac n d k) + (define (cf-acc n d k i) + (if (= k i) + (/ (n i) (d i)) + (/ (n i) (+ (d i) (cf-acc n d k (+ i 1)))))) + (cf-acc n d k 0)) + +(define (tan-cf x k) + (cont-frac (lambda (i) (if (= i 0) + x + (- (* x x)))) + (lambda (i) (+ 1.0 (* 2.0 i))) + k)) diff --git a/ex-1.40.scm b/ex-1.40.scm new file mode 100644 index 0000000..eb0e8a0 --- /dev/null +++ b/ex-1.40.scm @@ -0,0 +1,7 @@ +#lang sicp + +(define (cubic a b c) + (lambda (x) (+ (* x x x) + (* a x x) + (* b x) + c))) diff --git a/ex-1.41.scm b/ex-1.41.scm new file mode 100644 index 0000000..6ee1afb --- /dev/null +++ b/ex-1.41.scm @@ -0,0 +1,12 @@ +#lang sicp +(define (double f) + (lambda (x) (f (f x)))) + +; double doubles the function application, so when you do +; (double double) you actually get back a function which performs +; a (double (double f)) on a given f, in other words, it +; applies f 4 times. When we do this three times, +; (double (double double)) gives us a function, that for f gives +; (double (double (double (double f)))), which actually +; applies f sixteen times, +; so the result is 5+16 = 21. diff --git a/ex-1.42.scm b/ex-1.42.scm new file mode 100644 index 0000000..1da57c6 --- /dev/null +++ b/ex-1.42.scm @@ -0,0 +1,4 @@ +#lang sicp + +(define (compose f g) + (lambda (x) (f (g x)))) diff --git a/ex-1.43.scm b/ex-1.43.scm new file mode 100644 index 0000000..39d1de2 --- /dev/null +++ b/ex-1.43.scm @@ -0,0 +1,11 @@ +#lang sicp + +(define (identity x) x) + +(define (compose f g) + (lambda (x) (f (g x)))) + +(define (repeated f n) + (if (= n 0) + identity + (compose f (repeated f (- n 1))))) diff --git a/ex-1.44.scm b/ex-1.44.scm new file mode 100644 index 0000000..4c0a8fd --- /dev/null +++ b/ex-1.44.scm @@ -0,0 +1,9 @@ +#lang sicp + +(define (smooth f) + (define dx 0.0001) + (lambda (x) + (/ (+ (f (- x dx)) + (f x) + (f (+ x dx))) + 3))) diff --git a/ex-1.45.scm b/ex-1.45.scm new file mode 100644 index 0000000..e0ea076 --- /dev/null +++ b/ex-1.45.scm @@ -0,0 +1,81 @@ +#lang sicp +; here, I will prove an upper bound on the number of average +; dampings needed for a given n while calculating nth-root +; in other words, you might need fewer damps than what i prove +; but you definitely have enough damps with this method. + +; with n, we need the transform y -> x/y^(n-1) +; one thing which will guarrantee convergence is that the +; derivative of the transform is 0 < d < 1 AFTER the point of +; convergence we're looking for, for example +; derivative of this transform is for SQUARE ROOT is: +; transf: y -> x/y +; deriv: -(x/y^2), which for y>=sqrt(x) will give us a number: +; -1 <= N <= 0, so we can't guarrantee divergence. +; when we average damp, the deriv becomes: +; ( -(x/y^2) + 1 ) / 2, now it lands between 0 and 1. + +; for cube root, transform is y->x/y^2, deriv is: +; -2(x/y^3), this lands in the range -2 < d < 0 +; if we damp it once, we get the range -0.5 < d < 0.5, so we +; need to damp again to get the range 0.25 < d < 0.75 + +; in general for calculating the nth-root, we need the +; transform y -> x/y^(n-1), which will have the derivative: +; -(n-1)(x/y^n), the derivative will for y>(nth-root x) +; fall in the range -(n-1) < d < 0. +; Note that when we average damp the function, this range +; becomes -((n-1+1)/2) = -n/2 < d < 0.5, then +; ((-n/2)+1) / 2 < d < 0.75 +; when we play around we see that for n-1 = 1, we only need +; one damp, for n-1 = 2 or 3 we need two damps +; for n-1 = 4 or 5 or 6 or 7, we need three, in general +; for n >= 2, we need ceil(log2(n)), average damps + +; again, note, we might actually need fewer damps, this is +; just and upper-bound, however, luckily, we can never +; over-damp with this function when coming from the right +; because the upper bound for the derivative values will +; always be 0.5,0.75,0.875,.... < 1. +; so with enought damping we can always get a range of derivs +; in 0 < d < 1. + +(define (log2 x) + (/ (log x) (log 2))) + +(define tolerance 0.00001) + +(define (fixed-point f first-guess) + (define (close-enough? v1 v2) + (< (abs (- v1 v2)) tolerance)) + (define (try guess) + (let ((next (f guess))) + (if (close-enough? guess next) + next + (try next)))) + (try first-guess)) + +(define (identity x) x) + +(define (compose f g) + (lambda (x) (f (g x)))) + +(define (repeated f n) + (if (= n 0) + identity + (compose f (repeated f (- n 1))))) + +(define (average a b) + (/ (+ a b) 2)) + +(define (average-damp f) + (lambda (x) (average x (f x)))) + +; returns a procedure +(define (nth-root n) + (let* ((damp-number (ceiling (log2 n))) + (damps (repeated average-damp damp-number))) + (lambda (x) + (fixed-point (damps (lambda (y) + (/ x (expt y (- n 1))))) + (exact->inexact x))))) diff --git a/ex-1.46.scm b/ex-1.46.scm new file mode 100644 index 0000000..fcc8b47 --- /dev/null +++ b/ex-1.46.scm @@ -0,0 +1,24 @@ +#lang sicp +(define (iterative-improve good-enough? + improve) + (define (rec-procedure guess) + (define new-guess (improve guess)) + (if (good-enough? guess new-guess) + new-guess + (rec-procedure new-guess))) + rec-procedure) + +(define (square x) + (* x x)) + +(define (average a b) + (/ (+ a b) + 2)) + +(define (sqrt x) + (define tolerance 0.000001) + (define (good-enough? guess) + (< (abs (- (square guess) x)) tolerance)) + (define (improve guess) + (average guess (/ x guess))) + (iterative-improve good-enough? improve))