Add solutions to exercises from section 2.1

To be noted: the last two exercises, 2.15 and 2.16 were left unfinished,
and will be left for another time.
This commit is contained in:
Petar Kapriš 2025-02-04 22:16:43 +01:00
parent bc04031dff
commit 1b2b2dfec1
16 changed files with 391 additions and 0 deletions

8
ex-2.01.scm Normal file
View file

@ -0,0 +1,8 @@
#lang sicp
(define (make-rat n d)
(let ((g (gcd n d)))
(cond ((= d 0)
(error "Cannot make-rat with denominator 0"))
((< d 0) (cons (- (/ n g)) (- (/ d g))))
(else (cons (/ n g) (/ d g))))))

24
ex-2.02.scm Normal file
View file

@ -0,0 +1,24 @@
#lang sicp
(define (make-segment a b)
(cons a b))
(define (start-segment s)
(car s))
(define (end-segment s)
(cdr s))
(define (make-point x y)
(cons x y))
(define (x-point p)
(car p))
(define (y-point p)
(cdr p))
(define (average a b)
(/ (+ a b) 2.0))
(define (midpoint-segment s)
(make-point (average (x-point (start-segment s))
(x-point (end-segment s)))
(average (y-point (start-segment s))
(y-point (end-segment s)))))

34
ex-2.03.scm Normal file
View file

@ -0,0 +1,34 @@
#lang sicp
(define (make-point x y)
(cons x y))
(define (x-point p)
(car p))
(define (y-point p)
(cdr p))
; top-left point, bottom-right point representation
(define (tlbr-rect a b)
(cons 'tlbr (cons a b)))
; center point, width, height representation
(define (cpwh-rect p w h)
(cons 'cpwh
(cons p
(cons w h))))
(define (height rect)
(cond ((eq? 'cpwh (car rect)) (cdddr rect))
(else (abs (- (y-point (cadr rect))
(y-point (cddr rect)))))))
(define (width rect)
(cond ((eq? 'cpwh (car rect)) (caddr rect))
(else (abs (- (x-point (cadr rect))
(x-point (cddr rect)))))))
(define (perimeter rect)
(* 2 (+ (width rect) (height rect))))
(define (area rect)
(* (width rect) (height rect)))

4
ex-2.04.scm Normal file
View file

@ -0,0 +1,4 @@
#lang sicp
(define (cdr z)
(z (lambda (p q) q)))

29
ex-2.05.scm Normal file
View file

@ -0,0 +1,29 @@
#lang sicp
(define (cons a b)
(* (expt 2 a)
(expt 3 b)))
(define (car pair)
(if (= (remainder pair 3) 0)
(car (/ pair 3))
(log2 pair)))
(define (cdr pair)
(if (= (remainder pair 2) 0)
(cdr (/ pair 2))
(log3 pair)))
(define (log2 num)
(define (aux num acc)
(if (<= num 1)
acc
(aux (/ num 2) (+ acc 1))))
(aux num 0))
(define (log3 num)
(define (aux num acc)
(if (<= num 1)
acc
(aux (/ num 3) (+ acc 1))))
(aux num 0))

14
ex-2.06.scm Normal file
View file

@ -0,0 +1,14 @@
#lang sicp
(define one (lambda (f)
(lambda (x)
(f x))))
(define two (lambda (f)
(lambda (x)
(f (f x)))))
(define (+ a b)
(lambda (f)
(lambda (x)
((a f) ((b f) x)))))

7
ex-2.07.scm Normal file
View file

@ -0,0 +1,7 @@
#lang sicp
(define (lower-bound i)
(car i))
(define (upper-bound i)
(cdr i))

15
ex-2.08.scm Normal file
View file

@ -0,0 +1,15 @@
#lang sicp
(define (make-interval a b) (cons a b))
(define (lower-bound i)
(car i))
(define (upper-bound i)
(cdr i))
(define (sub-interval a b)
(make-interval (- (lower-bound a)
(upper-bound b))
(- (upper-bound a)
(lower-bound b))))

31
ex-2.09.scm Normal file
View file

@ -0,0 +1,31 @@
#lang sicp
#|
(define (add-interval x y)
(make-interval (+ (lower-bound x) (lower-bound y))
(+ (upper-bound x) (upper-bound y))))
(define (sub-interval a b)
(make-interval (- (lower-bound a) (upper-bound b))
(- (upper-bound a) (lower-bound b))))
Notice that in add-interval, the lower-bound is low-x + low-y.
Meanwhile the higher-bound is high-x + high-y = low-x + width-x
+ low-y + width-y = low-sum + (width-x + width-y).
So width-sum = width-x + width-y.
Similar logic applies to sub-interval.
For mul-interval it's enough to see that
(mul-interval (make-interval 1 2) (make-interval 3 4)) =
(3 . 8) -> width = 5
doesn't have the same width as:
(mul-interval (make-interval 3 4) (make-interval 3 4)) =
(9 . 16) -> width = 7
despite the fact that in both cases, the intervals have widths:
1 and 1.
|#
; This code is only here to pass hexlet's test, which I'm not sure is
; necessary.
(define (width x) (/ (- (upper-bound x) (lower-bound x))
2))

25
ex-2.10.scm Normal file
View file

@ -0,0 +1,25 @@
#lang sicp
(define (make-interval a b) (cons a b))
(define (lower-bound i)
(car i))
(define (upper-bound i)
(cdr i))
(define (mul-interval x y)
(let ((p1 (* (lower-bound x) (lower-bound y)))
(p2 (* (lower-bound x) (upper-bound y)))
(p3 (* (upper-bound x) (lower-bound y)))
(p4 (* (upper-bound x) (upper-bound y))))
(make-interval (min p1 p2 p3 p4)
(max p1 p2 p3 p4))))
(define (div-interval x y)
(if (<= (* (lower-bound y) (upper-bound y)) 0)
(error "division by zero")
(mul-interval
x
(make-interval (/ 1.0 (upper-bound y))
(/ 1.0 (lower-bound y))))))

75
ex-2.11.scm Normal file
View file

@ -0,0 +1,75 @@
#lang sicp
(define (make-interval a b) (cons a b))
(define (lower-bound i)
(car i))
(define (upper-bound i)
(cdr i))
; explanation for sgn-interval:
; an interval has sign 0 if it has negative and non-negative
; values (ie. it spans over zero)
; a sign of -1 if all of it's values are negative
; and a sign of 1 if all of it's values are non-negative
(define (sgn-interval a)
(let ((low-a (lower-bound a))
(upp-a (upper-bound a)))
(cond ((< upp-a 0) -1)
((>= low-a 0) 1)
(else 0))))
(define (mul-interval x y)
(let* ((sgn-x (sgn-interval x))
(sgn-y (sgn-interval y))
(sgn-pair (cons sgn-x sgn-y)))
(cond ((equal? sgn-pair '(-1 . -1))
(make-interval (* (upper-bound x)
(upper-bound y))
(* (lower-bound x)
(lower-bound y))))
((equal? sgn-pair '(-1 . 0))
(make-interval (* (lower-bound x)
(upper-bound y))
(* (lower-bound x)
(lower-bound y))))
((equal? sgn-pair '(-1 . 1))
(make-interval (* (lower-bound x)
(upper-bound y))
(* (upper-bound x)
(lower-bound y))))
((equal? sgn-pair '(0 . -1))
(make-interval (* (upper-bound x)
(lower-bound y))
(* (lower-bound x)
(lower-bound y))))
; the difficult case
((equal? sgn-pair '(0 . 0))
(let ((uu (* (upper-bound x) (upper-bound y)))
(ul (* (upper-bound x) (lower-bound y)))
(lu (* (lower-bound x) (upper-bound y)))
(ll (* (lower-bound x) (lower-bound y))))
(make-interval (min ul lu)
(max uu ll))))
((equal? sgn-pair '(0 . 1))
(make-interval (* (lower-bound x)
(upper-bound y))
(* (upper-bound x)
(upper-bound y))))
((equal? sgn-pair '(1 . -1))
(make-interval (* (upper-bound x)
(lower-bound y))
(* (lower-bound x)
(upper-bound y))))
((equal? sgn-pair '(1 . 0))
(make-interval (* (upper-bound x)
(lower-bound y))
(* (upper-bound x)
(upper-bound y))))
((equal? sgn-pair '(1 . 1))
(make-interval (* (lower-bound x)
(lower-bound y))
(* (upper-bound x)
(upper-bound y)))))))

23
ex-2.12.scm Normal file
View file

@ -0,0 +1,23 @@
#lang sicp
(define (make-interval a b) (cons a b))
(define (lower-bound i)
(car i))
(define (upper-bound i)
(cdr i))
(define (make-center-percent c p)
(make-interval (- c (* c p 1/100))
(+ c (* c p 1/100))))
(define (center i)
(/ (+ (lower-bound i) (upper-bound i)) 2))
(define (width i)
(/ (- (upper-bound i) (lower-bound i)) 2))
(define (percent i)
(* (/ (width i) (center i)) 100))

10
ex-2.13.txt Normal file
View file

@ -0,0 +1,10 @@
Let's limit our argument for positive numbers:
a+-wa * b+-wb = [(a-wa)*(b-wb), (a+wa)*(b+wb)]
[a*b - a*wb - b*wb + wa*wb, a*b + a*wb + b*wa + wa*wb]
if we assume wa*wb is insignificantly small, we get:
a*b+-(a*wb+b*wa)
tolerances are the following:
ta = wa/a
tb = wb/b
tab = (a*wb+b*wa)/(a*b) = (a*b*tb + a*b*ta)/(a*b) = ta+tb

72
ex-2.14.scm Normal file
View file

@ -0,0 +1,72 @@
#lang sicp
(define make-interval cons)
(define (lower-bound i)
(car i))
(define (upper-bound i)
(cdr i))
(define (sub-interval a b)
(make-interval (- (lower-bound a)
(upper-bound b))
(- (upper-bound a)
(lower-bound b))))
(define (mul-interval x y)
(let ((p1 (* (lower-bound x) (lower-bound y)))
(p2 (* (lower-bound x) (upper-bound y)))
(p3 (* (upper-bound x) (lower-bound y)))
(p4 (* (upper-bound x) (upper-bound y))))
(make-interval (min p1 p2 p3 p4)
(max p1 p2 p3 p4))))
(define (add-interval x y)
(make-interval (+ (lower-bound x) (lower-bound y))
(+ (upper-bound x) (upper-bound y))))
(define (div-interval x y)
(if (<= (* (lower-bound y) (upper-bound y)) 0)
(error "division by zero")
(mul-interval
x
(make-interval (/ 1.0 (upper-bound y))
(/ 1.0 (lower-bound y))))))
(define (par1 r1 r2)
(div-interval (mul-interval r1 r2)
(add-interval r1 r2)))
(define (par2 r1 r2)
(let ((one (make-interval 1 1)))
(div-interval
one (add-interval (div-interval one r1)
(div-interval one r2)))))
(define example-1 (make-interval 1 2))
(define example-2 (make-interval 0.999 1.001))
(div-interval example-1 example-1)
;(0.5 . 2.0)
(div-interval example-2 example-2)
;(0.9980019980019982 . 1.002002002002002)
; It's simplest to explain this using the previous result
; that the tolerance of a product of a*b, is roughly the
; sum of the tolerances (if the tolerances are small
; relative to the center point)
; We can also derive that the tolerance of 1/a is equal to
; the tolerance of a.
; Proof:
; a = [x-w,x+w], t_a = w/x
; 1/a = [1/(x+w), 1/(x-w)] =
; [(1/(x+w)) * (x-w)/(x-w), (1/(x-w)) * (x+w)/(x+w)] =
; [(x-w)/(x^2-w^2), (x+w)/(x^2-w^2)] =
; x/(x^2-w^2) +- w/(x^2-w^2)
; the tolerance of the product is then:
; (w/(x^2-w^2)) / (x/(x^2-w^2)) = w/x, same as t_a.
;
; This means, using the previous approximation, that the
; expression a/a = 1, rather than having a tolerance of 0
; is going to have a tolerance doubling that of a.

15
ex-2.15-NOT-DONE.txt Normal file
View file

@ -0,0 +1,15 @@
This is mostly explained in the previous exercise.
When it comes to par1 and par2 specifically, we should examine
the formulas themselves:
((R1+-t1*R1)*(R2+-t2*R2)) / (R1+-t1*R1 + R2+-t2*R2) =
(R1*R2 +-t1*R1*R2 +-t2*R2*R1 +-t1*t2*R1*R2) /
(R1+R2+-t1*R1+-t2*R2) =
(R1*R2 +-t1*R1*R2 +-t2*R2*R1 +-t1*t2*R1*R2) /
(R1+R2+-t1*R1+-t2*R2) * (R1+R2-+t1*R1-+t2*R2)/(R1+R2-+t1*R1-+t2*R2) =
(R1*R2 +-t1*R1*R2 +-t2*R2*R1 +-t1*t2*R1*R2) /
(R1+R2+-t1*R1+-t2*R2) * (R1+R2-+t1*R1-+t2*R2)/(R1+R2-+t1*R1-+t2*R2) =
1 / (1/(R1+-t1)+1/(R2+-t2)) =
1 / ((R1-+t1)/(R1^2-t1^2) + (R2-+t2)/(R2^2-t2^2)) =

5
ex-2.16-NOT-DONE.txt Normal file
View file

@ -0,0 +1,5 @@
One issue is the afformention reuse of intervals, another is
floating point arithmetic. In order to solve the problem of making
all expressions maximally precise, we would need to make a package that can
take a given arithmetic expression and minimize it. This is
probaly very hard but not impossible.