計算機科学のブログ

Building Abstractions with Data - Introduction to Data Abstraction - Extended Exercise: Interval Arithmetic - intervals, small percentage tolerance, approximate percentage tolerance of the product

Structure and Interpretation of Computer Programs: JavaScript Edition(Harold Abelson(著)、Gerald Jay Sussman(著)、Julie Sussman(著)、The MIT Press)のChapter 2(Building Abstractions with Data)、2.1(Introduction to Data Abstraction)、2.1.4(Extended Exercise: Interval Arithmetic)、Exercise 2.13解答を求めてみる。

c1、c2を中心、ε1、ε2を誤差の誤差のパーセンテージとする二つの区間について、

  • x_c1 = [c1 - c1 * ε1, c1 + c1 * ε1]
  • y_c2 = [c2 - c2 * ε2, c2 + c2 * ε2]

とし、その積を考える。(簡略化のために全ての端点は正の数とする。)

  • x_c1 * y_c2
  • [(c1 - c1 * ε1)(c2 - c2 * ε2), (c1 + c1 * ε1)(c2 + c2 * ε2)]
  • [c1 * c2 - c1 * c2 * ε2 - c1 * c2 * ε1 + c1 * c2 * ε1 * ε2, c1 * c2 + c1 * c2 * ε2 + c1 * c2 * ε1 + c1 * c2 * ε1 * ε2]
  • [c1 * c2 (1 - ε1 - ε2 + ε1 * ε2), c1 * c2 (1 + ε1 + ε2 + ε1 * ε2)]

ε1とε2が十分に小さいとき、ε1 * ε2を0とすると、

  • [c1 * c2 (1 - ε1 - ε2), c1 * c2 (1 + ε1 + ε2)]
  • [c1 * c2 - c1 * c2 (ε1 + ε2), c1 * c2 + c1 * c2 (ε1 + ε2)]

よって2つの区間の積の誤差は、2つの区間の誤差の和で近似できる。

実際に確認。

コード

function math_abs(x) {
    return Math.abs(x);
}
function display(x) {
    return console.log(x);
}
function pair(x, y) {
    return [x, y];
}
function head(z) {
    return z[0];
}
function tail(z) {
    return z[1];
}
function make_interval(x, y) {
    return pair(x, y);
}
function lower_bound(i) {
    return head(i);
}
function upper_bound(i) {
    return tail(i);
}
function make_center_percent(c, p) {
    const w = math_abs(c) * p / 100;
    return make_interval(c - w, c + w);
}
function center(i) {
    return (lower_bound(i) + upper_bound(i)) / 2;
}
function percent(i) {
    const u = upper_bound(i);
    const m = center(i);
    return (u - m) / m * 100;
}
function mul_interval(x, y) {
    const xl = lower_bound(x);
    const xu = upper_bound(x);
    const yl = lower_bound(y);
    const yu = upper_bound(y);
    if (xl < 0) {
        if (xu < 0) {
            if (yl < 0) {
                if (yu < 0) {
                    return make_interval(xu * yu, xl * yl);
                }
                return make_interval(xl * yu, xl * yl);
            }
            return make_interval(xl * yu, xu * yl);
        }
        if (yl < 0) {
            if (yu < 0) {
                return make_interval(xu * yl, xl * yl);
            }
            const p1 = xl * yu;
            const p2 = xu * yl;
            const p3 = xl * yl;
            const p4 = xu * yu;
            return make_interval(
                math_min(p1, p2),
                math_max(p3, p4)
            )
        }
        return make_interval(xl * yu, xu * yu);
    }
    if (yl < 0) {
        if (yu < 0) {
            return make_interval(xu * yl, xl * yu);
        }
        return make_interval(xu * yl, xu * yu);
    }
    return make_interval(xl * yl, xu * yu);
}

const tx = 10;
const ty = 5;
const x = make_center_percent(2, tx);
const y = make_center_percent(3, ty);
const xy = mul_interval(x, y);

display(x);
display(y);
display(xy);
display(percent(xy));
display(tx + ty);

入出力結果(Terminal, Zsh)

% node answer2.13.js
[ 1.8, 2.2 ]
[ 2.85, 3.15 ]
[ 5.13, 6.930000000000001 ]
14.925373134328362
15
%