これまでのiwaoさんの書き込みから判断すると、アセンブリ言語にも精通されている方のように思います。
アセンブリ言語を利用すれば、更に高速な処理を記述できます。
もしかしたら、既にご存知かもしれません。そのときはご容赦ください。
BCDをご存知でしょうか。Binary Coded Decimal(2進化10進数)といいます。
これはメモリ効率が悪いデータ形式ですが、今回のような処理にはもってこいです。
というか、これ以外に使い道があるのかどうか、疑問です。だれかご存知の方いらっしゃいます?
初めてBCDを知ったとき「○ンテルはどうしてこんな命令組み込んだんだろう」と首を傾げてしまいました(爆)
それは置いといて、、、
CPUの命令だから動作速度は最速(のハズ)です。また、除算を必要としません。
(ただし動作速度については検証しておりません。悪しからず。)
BCDは次のようなフォーマットです。
2進化10進数(BCD整数)は、範囲0~9の有効値を持つ符号なし4ビット整数である。
IA-32アーキテクチャは、1つ以上の汎用レジスタ内または1つ以上のx87 FPUレジスタ内にあるBCD整数の演算を定義している。
『IA-32 インテル アーキテクチャ・ソフトウェア・デベロッパーズ・マニュアル 上巻:基本アーキテクチャ(資料番号 253665-013J)第4章 データ型』より引用
簡単に言えば、10進数の一桁を表現するために4ビット使う、ということです。
例えば、10進数の52をBCDで表現すると、0x52となります。
x87 FPUレジスタは1つあたり10バイトの容量を持ちます。
先頭のバイトは符号バイトとして扱われるので、実質9バイトが利用できます。
ビットに換算すると72ビット、一桁4ビットだから、72÷4=18桁の10進数をBCDで表現できます。
この命令を利用する意義は大きいはずです。
こんな感じでいいとおもいます。
コード: 全て選択
unsigned int i = 98765; // 元の整数
unsigned char bcd[10]; // BCD整数を格納するバッファ
char d[18]; // 各桁の値を格納する配列 d[k]は 10 ^ k の位の値を保持する
int n;
__asm {
fild i
fbstp bcd
}
for(n = 0; n < 9; n++) {
d[n * 2] = bcd[n] & 0x0F;
d[n * 2 + 1] = (bcd[n] & 0xF0) >> 4;
}
FILDは整数をST(0)にロードする命令のニーモニック
FBSTPはST(0)をBCD形式に変換してストアしたあと、STをポップする命令のニーモニック
このアルゴリズムをDLL化するとよいとおもいます。
さすがに、コードの切れ端や実践コードモジュールに掲載できる程度を逸脱してしまいましたが・・・
[追記]
6月11日 12:18
上記コードは汎用形ですが、次のような無駄もあります。
- forループ内で乗算を2回行っている
- Long型の最大値は +2,147,483,647 であり、18桁を下回る
このような観点から、次のように最適化できます。
コード: 全て選択
int n2;
for(n = 0; n < 5; n++) { // 下位10桁を有効に扱えるよう、カウンタを調整
n2 = n << 1; // 2倍にはシフト演算を利用
d[n2] = bcd[n] & 0x0F;
n2++;
d[n2] = (bcd[n] & 0xF0) >> 4;
}