ループの中で、ある条件によって呼び出す関数を変えるって事をする時。
ループの中で条件判定をすると、同じ条件判定をすることになって、「無駄だなぁ」と思う。
条件判定後ループをすると同じ様なループを2つ書くことになるので「無駄だなぁ」と思う。
なので、条件判定を先にして関数ポインタを使って関数呼び出しを行うようにしている。
| #include <stdio.h> #include <time.h> #define DATA_SIZE 1000000 volatile int g; int ga[DATA_SIZE]; void func_a(int a) { g = a * a; } void func_b(int a) { g = a + a; } void test(int a) { int i; #if ALGORITHM == 1 for(i = 0; i < DATA_SIZE; i++) if(a == 0) func_a(ga[i]); else func_b(ga[i]); #elif ALGORITHM == 2 if(a == 0) for(i = 0; i < DATA_SIZE; i++) func_a(ga[i]); else for(i = 0; i < DATA_SIZE; i++) func_b(ga[i]); #else void (*func)(int) = a == 0 ? func_a : func_b; for(i = 0; i < DATA_SIZE; i++) func(ga[i]); #endif } int main(void) { int i; clock_t t; clock_t u = 0; for(i = 0; i < DATA_SIZE; i++) ga[i] = i; for(i = 0; i < 10; i++) { t = clock(); test(0); test(1); t = clock() - t; u += t; } printf("%d ms\n", u * 1000 / CLOCKS_PER_SEC); return 0; } |
EeePC上のgccでコンパイルして時間を計ってみると、
1:516ms / 2:438ms / 3:453ms
ま、こんなもんかな。因みに-O3で最適化すると、
1:109ms / 2:109ms / 3:234ms
何故こんなことになったのか不思議だったけど、アセンブラを出力させたらあっさり判明。
アルゴリズム1と2では最適化でfunc_a/func_bがインライン化されるけど、3では関数ポインタを使ったばかりにインライン化されず関数呼び出しが発生するから。
# それでも2の方が早くなりそうだけど、測定限界以下の差?プログラムでミスしてる?
勿論、コンパイラがインライン化できないような場合では最適化なしの時と同じような結果になるだろうけど、高速化しようと思ったら逆に遅くなる場合もあるのよね。
因みに、本当は例え実行する処理が1行しかなくてもifやforなどは必ず{}付ける派です。