計算機科学のブログ

Building Abstractions with Data - Introduction to Data Abstraction - Extended Exercise: Interval Arithmetic - tolerance, percent

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.14解答を求めてみる。

誤差が発生する関数の呼び出しが増えるほど、誤差が大きくなるから計算結果が異なる。

実際に計算して確認。

コード

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 add_interval(x, y) {
    return make_interval(
        lower_bound(x) + lower_bound(y),
        upper_bound(x) + upper_bound(y)
    );
}
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);
}
function div_interval(x, y) {
    return mul_interval(
        x,
        make_interval(
            1 / upper_bound(y),
            1 / lower_bound(y)
        )
    );
}
function par1(r1, r2) {
    return div_interval(
        mul_interval(r1, r2),
        add_interval(r1, r2)
    );
}
function par2(r1, r2) {
    const one = make_interval(1, 1);
    return div_interval(
        one,
        add_interval(
            div_interval(one, r1),
            div_interval(one, r2)
        )
    );
}

const x = make_center_percent(100, 0);
const y = make_center_percent(200, 0);
display(x);
display(y);
display(par1(x, y));
display(par2(x, y));

const r1 = make_center_percent(100, 1);
const r2 = make_center_percent(200, 1);
display(r1);
display(r2);
display(par1(r1, r2));
display(par2(r1, r2));

入出力結果(Terminal, Zsh)

% node answer2.14.js
[ 100, 100 ]
[ 200, 200 ]
[ 66.66666666666667, 66.66666666666667 ]
[ 66.66666666666667, 66.66666666666667 ]
[ 99, 101 ]
[ 198, 202 ]
[ 64.6930693069307, 68.69360269360268 ]
[ 66, 67.33333333333334 ]
%