2020-10-26 02:40:51 +01:00
|
|
|
(display "ex-2.7 - Start of extended exercise interval arithmetic\n")
|
|
|
|
|
2020-10-28 15:57:13 +01:00
|
|
|
(define (make-interval a b) (cons (min a b) (max a b)))
|
|
|
|
(define (lower-bound i) (min (car i) (cdr i)))
|
|
|
|
(define (upper-bound i) (max (car i) (cdr i)))
|
|
|
|
(define (print-interval i)
|
|
|
|
(display "[")
|
|
|
|
(display (lower-bound i))
|
|
|
|
(display ", ")
|
|
|
|
(display (upper-bound i))
|
|
|
|
(display "]"))
|
|
|
|
|
|
|
|
(define (add-interval x y)
|
|
|
|
(make-interval (+ (lower-bound x) (lower-bound y))
|
|
|
|
(+ (upper-bound x) (upper-bound y))))
|
|
|
|
|
|
|
|
(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)
|
|
|
|
(mul-interval x
|
|
|
|
(make-interval (/ 1.0 (upper-bound y))
|
|
|
|
(/ 1.0 (lower-bound y)))))
|
|
|
|
|
|
|
|
(define i (make-interval 2. 3.))
|
|
|
|
(print-interval i) (newline)
|
|
|
|
(print-interval (add-interval i i))
|
|
|
|
(newline)
|
|
|
|
|
2020-10-26 02:40:51 +01:00
|
|
|
(display "\nex-2.8\n")
|
|
|
|
|
2020-10-28 15:57:13 +01:00
|
|
|
; For subtraction the lower bound could be the lower bound of the first
|
|
|
|
; interval minus the upper bound of the second interval. The upper bound
|
|
|
|
; is the upper bound of the first interval minux the lower bound of the second
|
|
|
|
; interval.
|
|
|
|
|
|
|
|
(define (sub-interval x y)
|
|
|
|
(make-interval (- (lower-bound x) (upper-bound y))
|
|
|
|
(- (upper-bound x) (lower-bound y))))
|
|
|
|
(print-interval (sub-interval i i))
|
|
|
|
(newline)
|
|
|
|
|
2020-10-26 02:40:51 +01:00
|
|
|
(display "\nex-2.9\n")
|
|
|
|
|
2020-10-28 15:57:13 +01:00
|
|
|
(define (width-interval i)
|
|
|
|
(/ (abs (- (upper-bound i) (lower-bound i))) 2.))
|
|
|
|
|
|
|
|
(define i (make-interval 2. 3.))
|
|
|
|
(define j (make-interval 6. 7.))
|
|
|
|
(display "Width of i and j:\n")
|
|
|
|
(display (width-interval i)) (newline)
|
|
|
|
(display (width-interval j)) (newline)
|
|
|
|
|
|
|
|
(display "Width after addition and subtraction:\n")
|
|
|
|
(display (width-interval (add-interval i j))) (newline)
|
|
|
|
(display (width-interval (sub-interval j i))) (newline)
|
|
|
|
|
|
|
|
(display "Width after multiplication and division\n")
|
|
|
|
(display (width-interval (mul-interval i j))) (newline)
|
|
|
|
(display (width-interval (div-interval j i))) (newline)
|
|
|
|
|
|
|
|
; For addition and subtraction the width is the sum of the widths of the input
|
|
|
|
; intervals. For multiplication and division there is no simple arithmetic
|
|
|
|
; operation to get the width of the result.
|
|
|
|
|
|
|
|
; Moreover, when two intervals width the same width are multiplied the
|
|
|
|
; resulting width may be different to two other intervals with the same widths
|
|
|
|
; being multiplied.
|
|
|
|
|
2020-10-26 02:40:51 +01:00
|
|
|
(display "\nex-2.10\n")
|
|
|
|
|
2020-10-28 15:57:13 +01:00
|
|
|
(define i (make-interval 12 18))
|
|
|
|
(define j (make-interval -6 6))
|
|
|
|
|
|
|
|
(print-interval (div-interval i j)) (newline)
|
|
|
|
|
|
|
|
(define (div-interval x y)
|
|
|
|
(if (and (< (lower-bound y) 0) (> (upper-bound y) 0))
|
|
|
|
(error "Divider interval spans zero")
|
|
|
|
(mul-interval x
|
|
|
|
(make-interval (/ 1.0 (upper-bound y))
|
|
|
|
(/ 1.0 (lower-bound y))))))
|
|
|
|
; (div-interval i j) -> Error
|
|
|
|
|
2020-10-26 02:40:51 +01:00
|
|
|
(display "\nex-2.11\n")
|
|
|
|
|
2020-10-28 15:57:13 +01:00
|
|
|
(define (old-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 (mul-interval x y)
|
|
|
|
(let ((lx (lower-bound x))
|
|
|
|
(ux (upper-bound x))
|
|
|
|
(ly (lower-bound y))
|
|
|
|
(uy (upper-bound y))
|
|
|
|
(p? (lambda (x) (>= x 0)))
|
|
|
|
(n? (lambda (x) (< x 0))))
|
|
|
|
(cond
|
|
|
|
((and (p? lx) (p? ux) (p? ly) (p? uy)) (make-interval (* lx ly) (* ux uy))) ; 1
|
|
|
|
((and (n? lx) (n? ux) (n? ly) (n? uy)) (make-interval (* ux uy) (* lx ly))) ; 2
|
|
|
|
((and (n? lx) (p? ux) (n? ly) (p? uy)) (make-interval (min (* lx uy) (* ux ly))
|
|
|
|
(max (* lx ly) (* ux uy)))) ; 3 - hard case
|
|
|
|
((and (p? lx) (p? ux) (n? ly) (n? uy)) (make-interval (* ux uy) (* lx ly))) ; 4
|
|
|
|
((and (p? lx) (p? ux) (n? ly) (p? uy)) (make-interval (* ux ly) (* ux uy))) ; 5
|
|
|
|
((and (n? lx) (n? ux) (p? ly) (p? uy)) (make-interval (* lx uy) (* ux ly))) ; 6
|
|
|
|
((and (n? lx) (n? ux) (n? ly) (p? uy)) (make-interval (* ux uy) (* ux ly))) ; 7
|
|
|
|
((and (n? lx) (p? ux) (n? ly) (n? uy)) (make-interval (* ux uy) (* lx uy))) ; 8
|
|
|
|
((and (n? lx) (p? ux) (p? ly) (p? uy)) (make-interval (* lx uy) (* ux uy))) ; 9
|
|
|
|
(else (error "Missing implementation.")))))
|
|
|
|
|
|
|
|
(print-interval (mul-interval (make-interval 1 3) (make-interval 3 5))) (newline)
|
|
|
|
(print-interval (mul-interval (make-interval -1 -3) (make-interval -3 -5))) (newline)
|
|
|
|
|
|
|
|
; I copied the following from http://community.schemewiki.org/?sicp-ex-2.11 to test
|
|
|
|
; my implementation. The internet is amazing. Thanks jz!
|
|
|
|
(define (eql-interval? a b)
|
|
|
|
(and (= (upper-bound a) (upper-bound b))
|
|
|
|
(= (lower-bound a) (lower-bound b))))
|
|
|
|
|
|
|
|
; Fails if the new mult doesn't return the same answer as the old
|
|
|
|
; naive mult.
|
|
|
|
(define (ensure-mult-works aH aL bH bL)
|
|
|
|
(let ((a (make-interval aL aH))
|
|
|
|
(b (make-interval bL bH)))
|
|
|
|
(if (eql-interval? (old-mul-interval a b)
|
|
|
|
(mul-interval a b))
|
|
|
|
true
|
|
|
|
(error "new mult returns different value!"
|
|
|
|
a
|
|
|
|
b
|
|
|
|
(old-mul-interval a b)
|
|
|
|
(mul-interval a b)))))
|
|
|
|
|
|
|
|
|
|
|
|
; The following is overkill, but it found some errors in my work. The first
|
|
|
|
; two #s are the endpoints of one interval, the last two are the other's.
|
|
|
|
; There are 3 possible layouts (both pos, both neg, one pos one neg), with 0's
|
|
|
|
; added for edge cases (pos-0, 0-0, 0-neg).
|
|
|
|
|
|
|
|
(ensure-mult-works +10 +10 +10 +10)
|
|
|
|
(ensure-mult-works +10 +10 +00 +10)
|
|
|
|
(ensure-mult-works +10 +10 +00 +00)
|
|
|
|
(ensure-mult-works +10 +10 +10 -10)
|
|
|
|
(ensure-mult-works +10 +10 -10 +00)
|
|
|
|
(ensure-mult-works +10 +10 -10 -10)
|
|
|
|
|
|
|
|
(ensure-mult-works +00 +10 +10 +10)
|
|
|
|
(ensure-mult-works +00 +10 +00 +10)
|
|
|
|
(ensure-mult-works +00 +10 +00 +00)
|
|
|
|
(ensure-mult-works +00 +10 +10 -10)
|
|
|
|
(ensure-mult-works +00 +10 -10 +00)
|
|
|
|
(ensure-mult-works +00 +10 -10 -10)
|
|
|
|
|
|
|
|
(ensure-mult-works +00 +00 +10 +10)
|
|
|
|
(ensure-mult-works +00 +00 +00 +10)
|
|
|
|
(ensure-mult-works +00 +00 +00 +00)
|
|
|
|
(ensure-mult-works +00 +00 +10 -10)
|
|
|
|
(ensure-mult-works +00 +00 -10 +00)
|
|
|
|
(ensure-mult-works +00 +00 -10 -10)
|
|
|
|
|
|
|
|
(ensure-mult-works +10 -10 +10 +10)
|
|
|
|
(ensure-mult-works +10 -10 +00 +10)
|
|
|
|
(ensure-mult-works +10 -10 +00 +00)
|
|
|
|
(ensure-mult-works +10 -10 +10 -10)
|
|
|
|
(ensure-mult-works +10 -10 -10 +00)
|
|
|
|
(ensure-mult-works +10 -10 -10 -10)
|
|
|
|
|
|
|
|
(ensure-mult-works -10 +00 +10 +10)
|
|
|
|
(ensure-mult-works -10 +00 +00 +10)
|
|
|
|
(ensure-mult-works -10 +00 +00 +00)
|
|
|
|
(ensure-mult-works -10 +00 +10 -10)
|
|
|
|
(ensure-mult-works -10 +00 -10 +00)
|
|
|
|
(ensure-mult-works -10 +00 -10 -10)
|
|
|
|
|
|
|
|
(ensure-mult-works -10 -10 +10 +10)
|
|
|
|
(ensure-mult-works -10 -10 +00 +10)
|
|
|
|
(ensure-mult-works -10 -10 +00 +00)
|
|
|
|
(ensure-mult-works -10 -10 +10 -10)
|
|
|
|
(ensure-mult-works -10 -10 -10 +00)
|
|
|
|
(ensure-mult-works -10 -10 -10 -10)
|
|
|
|
|
|
|
|
(display "Run mul-interval tests successfully") (newline)
|
|
|
|
|
2020-10-26 02:40:51 +01:00
|
|
|
(display "\nex-2.12\n")
|
|
|
|
|
2020-10-28 15:57:13 +01:00
|
|
|
(define (make-center-width c w)
|
|
|
|
(make-interval (- c w) (+ c w)))
|
|
|
|
|
|
|
|
(define (center i)
|
|
|
|
(/ (+ (lower-bound i) (upper-bound i)) 2))
|
|
|
|
|
|
|
|
(define (width i)
|
|
|
|
(/ (- (upper-bound i) (lower-bound i)) 2))
|
|
|
|
|
|
|
|
(define (make-center-percent c p)
|
|
|
|
(make-center-width c (* c (/ p 100))))
|
|
|
|
|
|
|
|
(define (percent i)
|
|
|
|
(abs (* (/ (width-interval i) (center i)) 100)))
|
|
|
|
|
|
|
|
(define i (make-center-percent -10 10.0))
|
|
|
|
(print-interval i) (newline)
|
|
|
|
(display (percent i)) (newline)
|
|
|
|
|
2020-10-26 02:40:51 +01:00
|
|
|
(display "\nex-2.13\n")
|
|
|
|
|
2020-10-28 15:57:13 +01:00
|
|
|
; Show that under the assumption of small percentage tolerances there is a
|
|
|
|
; simple formula for the approximate percentage tolerance of the product of two
|
|
|
|
; intervals in terms of the tolerances of the factors. You may simplify the
|
|
|
|
; problem by assuming that all numbers are positive.
|
|
|
|
|
|
|
|
; The simpliefied formual is: pz = px + py see journal 2018 page 128 for proof
|
|
|
|
(let ((a (make-center-percent 5 0.8))
|
|
|
|
(b (make-center-percent 10 0.6)))
|
|
|
|
(display (percent (mul-interval a b))) (newline)
|
|
|
|
(display (+ 0.008 0.006)) (newline)
|
|
|
|
(newline))
|
|
|
|
|
|
|
|
(newline) (display "Excercise 2.14") (newline)
|
|
|
|
|
|
|
|
(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 (print-res r)
|
|
|
|
(display (center r))
|
|
|
|
(display "+-")
|
|
|
|
(display (percent r))
|
|
|
|
(display "%")
|
|
|
|
(newline))
|
|
|
|
|
|
|
|
(define (diff_par r1 r2)
|
|
|
|
(let ((rp1 (par1 r1 r2))
|
|
|
|
(rp2 (par2 r1 r2)))
|
|
|
|
(print-res rp1)
|
|
|
|
(print-res rp2)))
|
|
|
|
|
|
|
|
(diff_par (make-center-percent 5 0.01) (make-center-percent 3 0.09))
|
|
|
|
(newline)
|
|
|
|
(diff_par (make-center-percent 60000000 0.5) (make-center-percent 3000 0.5))
|
|
|
|
|
|
|
|
(newline)
|
|
|
|
(let ((a (make-center-percent 33 0.5))
|
|
|
|
(b (make-center-percent 17 0.8)))
|
|
|
|
(print-res (add-interval a b))
|
|
|
|
(print-res (mul-interval a b))
|
|
|
|
(print-res (sub-interval a b))
|
|
|
|
(print-res (div-interval a b))
|
|
|
|
(newline))
|
|
|
|
|
|
|
|
(let ((a (make-center-percent 1000 0.5))
|
|
|
|
(b (make-center-percent 1000 0.5)))
|
|
|
|
(print-res (div-interval a a))
|
|
|
|
(print-res (div-interval a b))
|
|
|
|
(newline))
|
|
|
|
|
|
|
|
|
|
|
|
(display "Excercise 2.15") (newline)
|
|
|
|
|
|
|
|
(display
|
|
|
|
" Eva is right, because every variable reintroduced to the system
|
|
|
|
increases the uncertainty of the interval. Thus the less a variable
|
|
|
|
is used the less uncertainty and the tighter the bounds.") (newline)
|
|
|
|
|
|
|
|
(define (square-interval i)
|
|
|
|
(make-interval 0 (square (upper-bound i))))
|
2020-10-26 02:40:51 +01:00
|
|
|
|
2020-10-28 15:57:13 +01:00
|
|
|
(newline)
|
|
|
|
(print-interval (mul-interval (make-interval -1 1) (make-interval -1 1)))
|
|
|
|
(newline)
|
|
|
|
(print-interval (square-interval (make-interval -1 1)))
|
|
|
|
(newline)
|
2020-10-26 02:40:51 +01:00
|
|
|
|
|
|
|
(display "\nex-2.16\n")
|
2020-10-28 15:57:13 +01:00
|
|
|
(display
|
|
|
|
" This is the hard problem of interval arithmetic. One way to avoid
|
|
|
|
the issue is to change the input term so that each interval only
|
|
|
|
occurs once. That way accounting for an interval multiple times can
|
|
|
|
be avoided.")
|
2020-10-26 02:40:51 +01:00
|
|
|
|