atoi()関数の高速化
エラー処理がないとかイロイロ嫌われているatoi()関数ではありますが、いまだによく使います。 また、呼び出し回数が多いこともあり、昔から高速化を行っていました。 まあ、最近のCPUでは、何千万回とかやらないと差がわかりにくくなっていますが、少しでも高速なことは良いことです。
プログラムテスト仕様
atoi()関数に限らず、高速チューンを施す場合、まずテスト用のプログラムを作成します。 今回作ったのは、windows用で、以下のようなモノです。
// // atoi() を極める // copyright(c)2011 by 無作為研究所 http://www.faicha.com/ // #include "windows.h" #include "stdlib.h" char* srcbuf; int* dstbuf; int* ansbuf; #define N 1000000 #define M 999999 // // データエリアの初期化 // void init_data(void ) { int i; srcbuf = malloc(N * 8); // 8バイトづつ文字列を入れる dstbuf = malloc(N * sizeof(int)); // 整数型 ansbuf = malloc(N * sizeof(int)); // 整数型 for (i = 0;i < N;i++) { // 0からM−1の数文字列をいれておく sprintf(srcbuf+i*8,"%d",((rand()*rand()+rand())% M)-M/2); // 正解を求めておく ansbuf[i] = atoi(srcbuf+i*8); } return ; } // // 解答エリアのクリア // void clear_data(void ) { int i; for (i = 0;i < N;i++) { dstbuf[i] = 0; } return ; } // // 答え合わせ // void check_data(void ) { int i; for (i = 0;i < N;i++) { if (dstbuf[i] != ansbuf[i]) { printf("Wrong answer: string=%s answer=%s bad answer=%d (position=%d)\n", srcbuf+i*8,ansbuf[i],dstbuf[i],i); exit(1); } } return ; } extern int atoi_01(char* p); // // atoiによる処理 // void atoi_00_loop(void) { int i; for (i = 0;i < N;i++) { dstbuf[i] = atoi(srcbuf+i*8); } return ; } void atoi_01_loop(void) { int i; for (i = 0;i < N;i++) { dstbuf[i] = atoi_01(srcbuf+i*8); } return ; } // // 計測ルーチン // int check_speed(void(*callback)(void)) { DWORD t1,t2; while(1) { clear_data(); t1 = GetTickCount(); callback(); t2 = GetTickCount(); check_data(); if (t1 <= t2) break; } return t2 - t1; } // // メインエントリー // int main(int argc,char ** argv) { int i,j,spd1,spd2; init_data(); spd1 = 0; for (i = 0;i < 10;i++) { spd1 += check_speed(atoi_00_loop); } spd1 /= 10; printf("atoi_00(標準ライブラリ)での処理時間:%d[mS]\n",spd1); spd2 = 0; for (i = 0;i < 10;i++) { spd2 += check_speed(atoi_01_loop); } spd2 /= 10; printf("atoi_01(高速ライブラリ)での処理時間:%d[mS]\n",spd2); printf("標準ライブラリからの高速化 %G%%\n",100.0*((1.0/(double)spd2) / (1.0/(double)spd1))); return 0; }
check_speedという関数に、時間計測したい関数のポインタを渡して、これを10回呼び出し、平均値を計測しています。 計測対称は、atoi_00_loopと、atoi_01_loopという2つの関数で、それぞれ100万回、atoi関数と、atoi互換自作関数を呼び出します。atoi_01_loop関数内で呼び出されるatoi_01というのが、今回の研究対象である、atoiと互換性があって、速度をチューニングした関数です。
atoi_00(標準ライブラリ)での処理時間:101[mS] atoi_01(高速ライブラリ)での処理時間:49[mS] 標準ライブラリからの高速化 206.122%
上のプログラムをコンパイルして実行した結果がこちらです。
数回実行してみると、数mSは動作時間がバラつきますが、概ね200%程度の高速化を達成しているようです。
コンパイルはVisualC++で、オプティマイズオプションは /Ox(最大)で行っています。
プログラムソースとEXEをここに置きました。
ただ、高速atoi関数はobjのみ収録しておきましたので、どなたか、これより高速なヤツを作ってみてください。
また、当方の実行環境はWindowsVista(涙) Intel Centrino,4G Memですんで、環境によって、結果が違うなどの情報も頂けるとありがたいです。
しかし、ソースださなくっても、atoi1.obj解析したら、すぐに手口わかるなあ、こりゃ。
atoi_00(標準ライブラリ)での処理時間:54[mS] atoi_01(高速ライブラリ)での処理時間:24[mS] 標準ライブラリからの高速化 225%
知り合いのマシン(XP SP3 / Core 2 Quad @3.0GHz / MEM 4G)で試してもらったらこうなったらしいです。 みんないいマシン使っているんですね。
atoi_00(標準ライブラリ)での処理時間:70[mS] atoi_01(高速ライブラリ)での処理時間:23[mS] 標準ライブラリからの高速化 304.348%
さらに、知り合いのマシン(Win7-32bit / Athlon IIx4 630 / MEM 4G[3G認識])で試してもらったらこうなったらしいです。 これまた、不思議な結果だなあ。
無作為研究所トップページに戻る