デジタルちんぶろぐ

デジタルな話題

ホーム 連絡をする 同期する ( RSS 2.0 ) Login
投稿数  268  : 記事  0  : コメント  4419  : トラックバック  79

ニュース


技術以外は
ちんぶろぐ

記事カテゴリ

書庫

日記カテゴリ

ループの中で、ある条件によって呼び出す関数を変えるって事をする時。

ループの中で条件判定をすると、同じ条件判定をすることになって、「無駄だなぁ」と思う。

条件判定後ループをすると同じ様なループを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などは必ず{}付ける派です。

投稿日時 : 2008年2月13日 0:31

コメント

# re: 高速化ぁ 2008/02/14 1:39 けろ-みお
>void (*func)(int) = a == 0 ? func_a : func_b;

これはいいですね。
test()の引数であるaが0なら、func_a、
0以外ならfunc_bを呼ぶと。
どちらを呼ぶのかについては、*funcという関数ポインタに入れてるわけですね。

久々にC言語のソースをまともに読んでしまいましたw


# re: 高速化ぁ 2008/02/14 21:48 スーパーあんどちん
>> けろーみおさん
こういう場合には結構良い方法だと思ってますから、いいと言って貰えると嬉しいです。
人によっては「読みにくい」と不評な場合もあるので。


Post Feedback

タイトル
名前
Url:
コメント: