引き算を使わずに引き算する

引き算(ry

というわけで前回の続きになります。今回は引き算を使わずに引き算をしてみましょう。

まずは足し算の時と同様に論理式をそのままコードに起こしてみましょう。現在の桁がどういう論理関係にあるのかと、繰り下がり(ボロー)がどういう論理関係にあるのかに着目すれば簡単です。

int sub(int a, int b)
{
    while (b != 0)
    {
        int c = (~a & b) << 1;
        a ^= b;
        b = c;
    }
    return a;
}

いろいろ問題はあるのですが、実は add() を使えばもっと簡単に書けます。

int sub2(int a, int b)
{
    return add(a, add(~b, 1));
}

算数の基本ですが、引数 b をマイナスにして足せば a - b の引き算になります。上のコードでは b の 2の補数を計算して「b をマイナスにして」います。2の補数は「全ビットを反転して1を足」せば計算できます。上のコードは「1を足す」にも add() を使っているため非常に高価になっています。しかしマシン語レベルなら (Z80 なら INC 命令) 1個で書きますので、本来ならばここまで高価ではありません。

このコードが面白いのは、同じ事をやるにしても異なるアプローチがあり、それぞれに長所・短所・特徴があるという点でしょう。

さて、次回はいよいよ割り算(当初のゴール)にいってみますかね。