読者です 読者をやめる 読者になる 読者になる

32ビット環境で64ビット整数を扱う (減法編)

32ビット環境で64ビット整数を扱う (加法編) の続き。
今回は、加法のコードに少し手を加えて、減法を行う関数を作成します。

念のため、前回のエントリで使用した64ビット整数を表現するための構造体 QWORD の定義を再掲します。

qword.h
#ifndef __QWORD_H__
#define __QWORD_H__

//32ビット整数
typedef unsigned long DWORD;

//64ビット整数
typedef struct {
    DWORD dwLow;  //下位32ビット
    DWORD dwHigh; //上位32ビット
} QWORD;

#undef //__QWORD_H__
//[EOF]

2の補数

減算というのは、第二オペランドの符合を反転させた加算と等価です。 即ち、

x - yx + (-y)

ということ。 そのため、符合を反転する機能を作れば、前回作った加算プログラムのロジックを使いまわすことができます。

一般的に、整数値の符合反転には2の補数と呼ばれる手法が用いられます。 減算を行うため、まずはこの2の補数を64ビット値に対して実行する関数を作成しましょう。

//二の補数
QWORD comp2(DWORD dwLow, DWORD dwHigh){

    QWORD qw;

    if (dwLow){
        qw.dwLow  =~dwLow + 1UL;
        qw.dwHigh =~dwHigh;
    }
    else {
        qw.dwLow  =0x0UL;
        qw.dwHigh =~dwHigh + 1UL;
    }

    return qw;
}

Wikipedia の解説にあるように、2の補数は「すべてのビットを反転させた値に 1を加える」ことで得られます。 その際、最後の「1を加える」操作によって発生する下位32ビットから上位32ビットへ「繰り上がり」を考慮する必要がありますが、繰り上がりが発生するのは

~dwLow == 0xFFFFFFFF ( ⇔ dwLow == 0x0U )

の場合だけなので、これを if による判定で処理しています。

減法

前節で作った、2の補数を求める関数 comp2 と、32ビット環境で64ビット整数を扱う (加法編) で作成した関数 add を用いて、減算を行う関数 sub を以下のように定義します。

//64ビット整数の減算
QWORD sub(QWORD qw1, QWORD qw2){
    return add(qw1, comp2(qw2.dwLow, qw2.dwHigh));
}

拍子抜けするほど簡単ですが、この柔軟な拡張性こそが「2の補数」という手法の偉大さなのです。

ちょっと次回予告

加法, 減法ときたので、次回は「乗法」の解説を行います。 しかし、この乗法は自分で実装してみた限りでも相当に複雑に複雑なので、上手く説明できるかどうか、些か心許ないところです。 分かりづらい場合は、ツッコミや質問をコメント欄に書き込んで頂ければ、補足・修正等の対応を致しますので、よろしくお願いします。

成田