スポンサード リンク

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

スポンサード リンク
-- : -- : -- | スポンサー広告 | page top↑
スポンサード リンク

「ループはポインタ使った方が速い」とは限らない

C言語で配列の各要素へ順番にアクセスするために、indexを用いてループを回す次のようなコードをしばしば書くと思います。


  int i;
  for(i=0; i < SIZE; i++)
    /* この中でa[i]とアクセスする。*/

しかし、次のようにポインタを用いてループを回すコードを時折目にします。


  int *p;
  for(p=&a[0]; p!=&a[SIZE]; p++) sum = (*p)*(*p);
    /* この中で*pとアクセスする。*/

このコーディングの理由としては「ポインタを使った方が速いから。」「C言語らしくてかっこいいから。」などが主だと思いますが、後者はともかくとして前者の主張は常に正しいとは限りません。

確かに、昔はindexでループを回して添え字を使って配列へアクセスするよりも、ポインタを使ってループを回した方が高速に実行できたようです。しかし、現在はコンパイラが最適化を頑張ってくれるのでどちらのコードも速度に大した差はないか、むしろ、ポインタでループを回すなど凝ったコードを書くと最適化の妨げとなってしまい、結果としてindexを使ってループを回すコードより低速になってしまうことがあります。

実際に実験をしてみましょう。ここでは次のような配列の和を計算するプログラムで計測をします。


#include < stdio.h >
#include "clock.h"
#define SIZE 1024
#define LOOP 1024

void func_i(int *a, int *dest) {
  int i, sum=0;
  for(i=0; i < SIZE; i++) sum += a[i];
  *dest = sum;
}

void func_p(int *a, int *dest) {
  int *p, sum=0;
  for(p=&a[0]; p!=&a[SIZE]; p++) sum += (*p);
  *dest = sum;
}

int main() {
  int i, a[SIZE], dest;
  double tclock, iclock, pclock;

  for(i=0; i < SIZE; i++) a[i] = i;

  start_counter();
  func_i(a, &dest);
  iclock = get_counter();

  for(i=0; i < LOOP; i++) {
    start_counter();
    func_i(a, &dest);
    tclock = get_counter();
    if(tclock < iclock) iclock = tclock;
  }
  
  printf("--- Index Code ---\n");
  printf(" clock = %f dest = %d\n", iclock, dest);
  
  start_counter();
  func_p(a, &dest);
  pclock = get_counter();

  for(i=0; i < LOOP; i++) {
    start_counter();
    func_p(a, &dest);
    tclock = get_counter();
    if(tclock < pclock) pclock = tclock;
  }

  printf("--- Pointer Code ---\n");
  printf(" clock = %f dest = %d\n", pclock, dest);

  return 0;
}

プログラムの先頭でincludeしているヘッダファイルclock.hはCPUのクロック数を測定するための関数start_counter()とget_counter()を呼び出すためのヘッダファイルです。某大学の授業で用いられているものなので、普通の方はこのプログラムをコピペしてそのままコンパイルしようとするとエラーがでます。

for(i=0; i < LOOP; i++)
というループを回して何度も測定を繰り返し、その最小値を取っています。これは、測定中にほかの処理の割り込みが発生して遅くなることはあるが、理想的な値より偶然速くなるということはないためです。

実行結果を以下に示します。


$ ./a
--- Index Code ---
 clock = 8955.000000 clock/element = 8.745117 dest = 523776
--- Pointer Code ---
 clock = 8538.000000 clock/element = 8.337891 dest = 523776

普通にコンパイルをして実行した場合は、ポインタで回すほうが若干ではありますが速いという結果がでました。

次に、gccの最適化オプション(-O2)をつけてコンパイルした実行ファイルを走らせました。


$ ./a
--- Index Code ---
 clock = 2161.000000 clock/element = 2.110352 dest = 523776
--- Pointer Code ---
 clock = 2176.000000 clock/element = 2.125000 dest = 523776

コンパイラの最適化により、2つのコードの速度はほぼ等しくなってしまいました。さらによく見ると、indexでループを回す方がわずかではありますが、ポインタで回すより速いという結果になりました。

このように、現在はポインタを使ってループを回すコードもindexで回すコードも実行速度に大差はなく、場合によってはコンパイラの最適化によってindexを使ったコードの方が(わずかにではありますが)速いことさえあるのです。

測定環境

私が測定に用いたマシンの主なスペックは以下の通りです。この実験の結果は環境によってことなることがあります。

  • CPU : Pentium M プロセッサ超低電圧版 753
  • RAM : 1024MB
  • コンパイラ : gcc (GCC) 3.4.4 (cygming special, gdc 0.12, using dmd 0.125)

参考にした書籍

C言語ポインタ完全制覇 (標準プログラマーズライブラリ)
C言語ポインタ完全制覇 (標準プログラマーズライブラリ)前橋 和弥

技術評論社 2001-01
売り上げランキング : 4923
おすすめ平均star


Amazonで詳しく見る
by G-Tools

C言語の書籍

プログラミング言語C ANSI規格準拠
プログラミング言語C ANSI規格準拠B.W. カーニハン D.M. リッチー 石田 晴久

共立出版 1989-06
売り上げランキング : 3998
おすすめ平均star


Amazonで詳しく見る
by G-Tools
新版 明解C言語 入門編
新版 明解C言語 入門編柴田望洋

ソフトバンククリエイティブ 2004-08-28
売り上げランキング : 2193
おすすめ平均star


Amazonで詳しく見る
by G-Tools

スポンサード リンク

テーマ:プログラミング - ジャンル:コンピュータ - ソーシャルブックマーク: この記事をクリップ! Yahoo!ブックマークに登録

00 : 36 : 04 | プログラミング-C/C++ | トラックバック(0) | コメント(2) | page top↑
<<配列の添え字チェック(安全なJavaと自己責任のC言語) | ホーム | SQLにおける「存在検査(EXISTS)」と「IN述語」の違い>>
コメント
管理人のみ閲覧できます
このコメントは管理人のみ閲覧できます
by: * 2008/02/14 01:51 * [ 編集] | page top↑

>管理人のみに見えるコメントを下さった方

ご指摘ありがとうございます。

恥ずかしいミスをしていました><
そして、コードを変更して実行してみたら私の環境でも通常時はポインタ版の方が速くなりました。

そこで、記事を加筆・修正しました。また、それに伴って、二乗和を求める関数を(一乗)和を求める関数に変更しました。

今後はなおいっそう正確な記事を書くように努めますので、これからも「情報科学を学ぶ大学生のブログ」をよろしくお願いします。
by: TBVector * 2008/02/14 17:49 * URL [ 編集] | page top↑

コメントの投稿














管理者にだけ表示を許可する

トラックバック
トラックバックURL
http://networkprogramming.blog18.fc2.com/tb.php/12-9def3917
この記事にトラックバックする(FC2ブログユーザー)
| ホーム |

プロフィール

TBVector

Author:TBVector

プロフィール

メールフォーム

記事検索

Google

最近の記事

人気の記事

過去の記事

カテゴリー

タグランキング

リンク

最近のコメント

最近のトラックバック

アクセスカウンタ

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。