計算機プログラムの構造と解釈 第二版 P53 問題2.9

文章が難しい。
頑張って読んでみるとこういうこと。

・二つの区間の和(または差)の幅は、足されるべき(または引かれるべき)区間の幅だけの関数であることを示せ。
・んで、乗算と除算についてはこれが成り立たないことを示す。


一つ目の「二つの区間の和の...」ってのは、
まず「幅」ってのは

区間の幅(width)は上限と下限の差の半分である。

ってある。


だので、ここで何を言ってるかというと、


ある区間1、区間2の足し算は、
区間1、区間2の「幅」だけで表現できる


ある区間1、区間2の引き算は、
区間1、区間2の「幅」のだけで表現できる


ってことを言ってるように、感じました。
ので


「w(x)」 : 区間xの幅。
「w(y)」 : 区間yの幅。
「x[u]」: xの大きい方の値
「x[l]」: xの大きい方の値
「y[u]」: yの大きい方の値
「y[l]」: yの大きい方の値

とする。
前提条件として、

x:w = (x[u] - x[l])/2
y:w = (y[u] - y[l])/2

とすると。


区間の和の幅は
前提として
(x+y)[u] = x[u] + y[u]
(x+y)[l] = x[l] + y[l]
をふまえて

w(x + y) = ( (x+y)[u] - (x+y)[l]) / 2
           = ( (x[u] - x[l]) + (y[u] - y[l]) )/2
           = (x[u] - x[l])/2 + (y[u] - y[l])/2
           = w(x) + w(y)

「区間x」と「区間y」の和の「幅」は、
「区間xの幅」と「区間yの幅」の和
と表現できる。




区間の差の幅は
前提として
(x-y)[u] = x[u] - y[l]
(x-y)[l] = x[l] - y[u]
をふまえて、

w(x - y) = ((x-y)[u] - (x-y)[l]) / 2
         = ( (x[u] - y[l]) - (x[l] - y[u]) ) / 2
         = (x[u] - y[l] - x[l] + y[u]) / 2
         = ( (x[u]- x[l]) + (y[u]- y[l]) ) / 2
         = (x[u] - x[l])/2 + (y[u] - y[l]) / 2
         = w(x) + w(y)

「区間x」と「区間y」の差の「幅」は、
「区間xの幅」と「区間yの幅」の和
と表現できる。



二つ目の「乗算と除算については....」
例えば幅が1になるような、区間の乗算と除算をやってみて
その出力された区間の幅を見てみれば、分かると感じた。



んでは、実装。

#!/usr/local/bin/gosh
;; -*- coding: utf-8 -*-

(use ggc.debug.trace)
(use math.mt-random)


;;P53
;;和
(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)))))


;;問題2-7
(define (make-interval a b) (cons a b)) 

(define (upper-bound interval)
  (max (car interval) (cdr interval)))


(define (lower-bound interval)
  (min (car interval) (cdr interval)))


;;問題2-8
;;差
(define (sub-interval x y)
  (make-interval (- (lower-bound x) (upper-bound y))
                 (- (upper-bound x) (lower-bound y))))


;;問題2-9
;;幅
(define (width interval)
  (/ (- (upper-bound interval) (lower-bound interval)) 2))



(define interval1 (make-interval 6 10))
(define interval2 (make-interval 3 5))
(define interval3 (make-interval 8 10))
(define interval4 (make-interval 98 100))
(define interval5 (make-interval 998 1000))



;; main
(define (main args)

  (newline)

  (display "(interval1): ")
  (display interval1)(newline)
  (display "(width interval1):")
  (display (width interval1))(newline)


  (display "(interval2): ")
  (display interval2)(newline)
  (display "(width interval2):")
  (display (width interval2))(newline)(newline)

  (display "区間の和の幅を二通りで作ってみる。")(newline)
  (display "幅同士の和を求める")(newline)
  (display "(+ (width interval1) (width interval2)): ")
  (display (+ (width interval1) (width interval2)))(newline)

  (display "区間の和の幅を求める")(newline)
  (display "(width (add-interval interval1 interval2)): ")
  (display (width (add-interval interval1 interval2)))(newline)(newline)

  (display "区間の差の幅を二通りで作ってみる。")(newline)
  (display "区間の幅同士の和を求めることで、「区間の差の幅」を求められる")(newline)
  (display "(+ (width interval1) (width interval2)): ")
  (display (+ (width interval1) (width interval2)))(newline)

  (display "区間の差の幅を求める")(newline)
  (display "(width (sub-interval interval1 interval2)): ")
  (display (width (sub-interval interval1 interval2)))(newline)

  (newline)
  (display "(interval3): ")
  (display interval3)(newline)
  (display "(width interval3):")
  (display (width interval3))(newline)

  (display "(interval4): ")
  (display interval4)(newline)
  (display "(width interval4):")
  (display (width interval4))(newline)

  (display "(interval5): ")
  (display interval5)(newline)
  (display "(width interval5):")
  (display (width interval5))(newline)(newline)


  (display "差は全部1だけど、各々答えは違う")(newline)
  (display "積")(newline)
  (display "(width (mul-interval interval3 interval4)): ")
  (display (width (mul-interval interval3 interval4)))(newline)

  (display "(width (mul-interval interval4 interval5)): ")
  (display (width (mul-interval interval4 interval5)))(newline)

  (display "商")(newline)
  (display "(width (div-interval interval4 interval3)): ")
  (display (width (div-interval interval4 interval3)))(newline)
  
  (display "(width (div-interval interval5 interval4)): ")
  (display (width (div-interval interval5 interval4)))(newline)
  
  (newline)
0)

実行

(interval1): (6 . 10)
(width interval1):2
(interval2): (3 . 5)
(width interval2):1

区間の和の幅を二通りで作ってみる。
幅同士の和を求める
(+ (width interval1) (width interval2)): 3
区間の和の幅を求める
(width (add-interval interval1 interval2)): 3

区間の差の幅を二通りで作ってみる。
区間の幅同士の和を求めることで、「区間の差の幅」を求められる
(+ (width interval1) (width interval2)): 3
区間の差の幅を求める
(width (sub-interval interval1 interval2)): 3

(interval3): (8 . 10)
(width interval3):1
(interval4): (98 . 100)
(width interval4):1
(interval5): (998 . 1000)
(width interval5):1

差は全部1だけど、各々答えは違う
積
(width (mul-interval interval3 interval4)): 108
(width (mul-interval interval4 interval5)): 1098
商
(width (div-interval interval4 interval3)): 1.3499999999999996
(width (div-interval interval5 interval4)): 0.11204081632653029