● 実行速度について
数値幅を小さくする
大きな数値を計算する事は本質的に時間が掛かります。通常、32bit 以下の値はCPUが直接扱えるので、計算はCPUの1命令で済み、尚且つ高速です(32bitCPUの場合)。しかし、32bit を超える場合は演算処理を構成する必要があるため、どうしても時間が掛かってしまいます。この処理時間は、数値幅が大きいほど長くなります。
プログラム側は fixed X の関数を組み合わせたり、複数回呼び出す等して計算を行うので、大きな数値幅で遅くなった fixed X 関数を数多く使用する事になり、その結果、全体の速度が低下します。
例えば、変数の値の最上位ビットが MSB に来るよう、全体を左シフトする処理を考えます。
例1.
FIXEDVAL val[SIZE];
・
・
・
/* 比較用:unsigned long の場合 */
if (fixed_nzero(val,SIZE)){ /* if (val){ */
while((val[SIZE - 1] & 0x80) == 0) /* while((val & 0x80000000UL) == 0) */
fixed_lshift1bit(val,SIZE); /* val <<= 1; */
} /* } */
fixed X は数値幅が任意に指定できるので、ほとんどの演算処理は関数内部でループを構成しています。比較関数とビット検索関数については、継続条件が偽になった時点でループを打ち切りますが、良く使われる計算関数等の主要な処理では、全ての領域にアクセスするまで繰り返されます。
ワーストケース val = 1 の場合は SIZE × 8 - 1 の回数分、SIZE バイトの領域へアクセスする事を繰り返す事になります。
if (fixed_nzero(val,SIZE)){
while((val[SIZE - 1] & 0x80) == 0) A
fixed_lshift1bit(val,SIZE); @
}
大まかなループ時間 = @数値幅分の関数処理 × A繰り返し回数
このような理由から、速度を求める場合は数値幅を小さくした方が良いのですが、プログラムによっては数値幅を減らせない場合もあります。その時は、最小限の関数呼び出しで目的を達成できるアルゴリズムを考える必要があります(@を減らせない場合はAを減らす事を検討する)。
上記の例の場合は、1 bit単位に処理する事を止め、位置を調べてから纏めてシフトするように変更する事ができます。
例2.
int top;
if ((top = fixed_bsr(val,SIZE)) > 0)
fixed_lshift(val,BIT - 1 - top,SIZE); /* BIT = SIZE * 8 */