アセンブラ vs C言語のテーブル引き 速度対決!
かずさんの提案で、
ビットの立ってる1を数える関数をアセンブラで書いた場合と、
8ビットでテーブルもっといて一発で引いた場合(ソースはうさ親さん提供のれさぴょんから)を比較してみました。
ソースは最後にあります。
アリーナに鍛え抜かれた強者たちが入ってきました。
筋肉と筋肉が雌雄を決するアスリート同士の頂上がちんこ対決。
筋肉番付、今スタートです!
さて注目の結果は?
C:\misaki>bench 0xaaaaaaaa PopCnt32 =1440000016 2.7s 0xaaaaaaaa PopCnt32b=1440000016 1.4s 0xa00aa00a PopCnt32 =720000008 1.3s 0xa00aa00a PopCnt32b=720000008 1.4s 0xa000a000 PopCnt32 =360000004 0.8s 0xa000a000 PopCnt32b=360000004 1.4s 0xffffffff PopCnt32 =-1414967264 4.6s 0xffffffff PopCnt32b=-1414967264 1.3s
ビットが全部立ってると断然テーブル引き(アセンブラ超遅い!)
ビットが16(半分)立っててもテーブル引きの勝ち
ビットが8個以下になってくるとアセンブラが速い
さすがにテーブル引きは、時間が一定なので安定してますね(^^;
実際、利きテーブルどのくらいビットが立ってるか?を考えると
上位16ビットは飛び利きなので、盤面の大部分で立ってませんので、
総合で考えるとアセンブラも盛り返すと思います。
ひとマスに利きが8個も乗ることなんかないですからね。
多くても5個ぐらいじゃないですか? 大部分は3個以下でしょう。
(先手と後手で利きテーブル別々ですから)
実際の所は連続自己対戦で決着ですか?
どうなんだろ? アセンブラ不利かも( ´Д`)
ビットボードでも使ってるんで、全面テーブル引きに切り替えるか?( ´Д`)
この勝負微妙。
審判委員の高砂部屋親方が土俵に入ってきました。
なにやら協議中のようです
勝負は、千秋楽の優勝決定戦に持ち越されました。
#include#include #include #include #include #include #include __forceinline int PopCnt32(unsigned int a) { __asm { mov ecx, dword ptr a xor eax, eax test ecx, ecx jz l1 l0: lea edx, [ecx - 1] inc eax and ecx, edx jnz l0 l1: } } const int Tbl[256]={ 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4, 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5, 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8 }; // xは、何ビット1が立っているか __forceinline int PopCnt32b(unsigned int x) { return Tbl[((unsigned char*)&x)[0]]+Tbl[((unsigned char*)&x)[1]]+Tbl[((unsigned char*)&x)[2]]+Tbl[((unsigned char*)&x)[3]]; } clock_t t_end; clock_t t_start; void main() { long count=90000000; t_start = clock(); int sum=0; for(long i=0;i<=count;i++) { sum+=PopCnt32(0xaaaaaaaa); } t_end = clock(); float thinktime=(float)(t_end - t_start) / CLOCKS_PER_SEC; printf("0xaaaaaaaa PopCnt32 =%d %4.1fs \n",sum,thinktime ); t_start = clock(); sum=0; for(long i=0;i<=count;i++) { sum+=PopCnt32b(0xaaaaaaaa); } t_end = clock(); thinktime=(float)(t_end - t_start) / CLOCKS_PER_SEC; printf("0xaaaaaaaa PopCnt32b=%d %4.1fs \n",sum,thinktime ); t_start = clock(); sum=0; for(long i=0;i<=count;i++) { sum+=PopCnt32(0xa000a000); } t_end = clock(); thinktime=(float)(t_end - t_start) / CLOCKS_PER_SEC; printf("0xa000a000 PopCnt32 =%d %4.1fs \n",sum,thinktime ); t_start = clock(); sum=0; for(long i=0;i<=count;i++) { sum+=PopCnt32b(0xa000a000); } t_end = clock(); thinktime=(float)(t_end - t_start) / CLOCKS_PER_SEC; printf("0xa000a000 PopCnt32b=%d %4.1fs \n",sum,thinktime ); t_start = clock(); sum=0; for(long i=0;i<=count;i++) { sum+=PopCnt32(0xffffffff); } t_end = clock(); thinktime=(float)(t_end - t_start) / CLOCKS_PER_SEC; printf("0xffffffff PopCnt32 =%d %4.1fs \n",sum,thinktime ); t_start = clock(); sum=0; for(long i=0;i<=count;i++) { sum+=PopCnt32b(0xffffffff); } t_end = clock(); thinktime=(float)(t_end - t_start) / CLOCKS_PER_SEC; printf("0xffffffff PopCnt32b=%d %4.1fs \n",sum,thinktime ); }