SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

japan.internet.com翻訳記事

JavaとC++のパフォーマンスを比較する

メモリ割り当て、ループ処理、浮動小数点演算を検証

浮動小数点ならどうなるか

 整数演算についてJavaとC++を比較しましたが、浮動小数点ならどうでしょうか。実際のところ、整数演算だけを行うアプリケーションを見つけるのは難しいでしょう。大抵のプログラムはどこかで(たとえ2つの数の平均値を求めるだけでも)浮動小数点演算を行います。

 先ほどの例と同じアプローチを使って、ランダムな浮動小数点数を生成し、それらを掛け合わせ、その所要時間を測定し、所要時間の平均値を算出してみましょう。

private void generateRandoms()
{
   randoms = new double[N_GENERATED];
   for( int i = 0; i < N_GENERATED; i++)
   {
      randoms[i] = Math.random();
   }
   
   multiply = new double[N_MULTIPLY];
   for( int i = 0; i < N_MULTIPLY; i++ )
   {
      multiply[i] = Math.random(); 
   }
}

private void javaCompute()
{
   double result = 0;
   for(int i = 0; i < N_MULTIPLY; i++)
   {
      for( int j = 0; j < N_GENERATED; j++ )
         result = randoms[j] * multiply[i];
   }
}

 上記のコード(DoubleMaths.java内)を筆者のラップトップで実行すると、次の結果が返されます。

Java computing took 47

 つまり、Javaで約10,000,000回の浮動小数点演算(乗算)を実行するのに平均で47ミリ秒(整数演算のおよそ2倍)を要したことになります。

 次にC++で試してみましょう(このコードはダウンロードファイル内のDoubleMathsプロジェクトに入っています)。

C computing took 0.001477

 前の例と同様、これもコンパイラで速度の最適化を行った結果です。最適化を無効にすると、次の結果が返されます。

C computing took 84.734633

 つまり、C++バージョンで最適化されたコンパイルを行った場合は、浮動小数点演算でもほとんど変わらないようです。それなりのコンパイラを使用すれば、整数演算と浮動小数点演算との差はほとんどなく、しかも生成されるコードは約25,000倍も速くなるでしょう。ただし、コンパイラを慎重に選ぶことが大事です。さもないと、Javaバージョンより2倍も遅くなってしまう可能性があります。

数値比較

 これまでのところ、計算の点ではC++の方が有利に見えます。しかし、数値比較ではどうでしょうか。次の2つの例で調べてみましょう。

  1. ifステートメントで2つの整数を使用する。このifステートメントでは、ステートメントが真の場合は、単純な割り当てを実行する
  2. ifステートメントのテスト対象で浮動小数点数を使用する

 最初の例では、ランダムな一連の整数を生成し、その配列をたどりながら前の数と現在の数を比較していきます。そして、現在の数の方が大きければ、それを変数に格納します。このようにすると、最終的に最も大きい数がわかるはずです。

 乱数の生成には、これまでの例と同じ方法を使用します。

/**
 * Generate random numbers
 */
private void generateRandoms()
{
   randoms = new int[N_GENERATED];
   
   for( int i = 0; i < N_GENERATED; i++)
   {
      randoms[i] = (int)(i * Math.random());
   }
}

 実行時間の平均値算出にも同じ方法を使用します。ただし、これを実行する方法は違います。もちろん、整数(数千万個)からなる大きな配列を割り当てて、それを上述のやり方で反復処理していくこともできますが、そうするとインデックスメモリアクセス時間という別の問題が生じます(これについては後ほど説明します)。そのため、代わりにいくつものint(この例では100個)からなる小さな配列を使用し、同じ演算を100,000回繰り返します。このようにして演算の時間を測定します。

 Javaのコードは次のようになります。

public static void main( String args[] )
{
   IntComparison comp = new IntComparison();
   comp.generateRandoms();
   long timeJava[] = new long[N_ITERATIONS];
   long start, end;
   for( int i = 0; i < N_ITERATIONS; i++ )
   {
      start = System.currentTimeMillis();
      for( int j = 0; j < N_REPEAT; j++ )
         comp.javaCompare();
      end = System.currentTimeMillis();
      timeJava[i] = (end - start);
   }
   System.out.println( "Java compare took " + testTime(timeJava) );
}

 筆者のラップトップで上記のコードを実行すると、次の結果が返されます。

Java compare took 50

 つまり、1千万(100,000×100)回の整数比較を実行するのに平均で50ミリ秒を要したことになります。

 C++でも同様の実装で結果を調べてみましょう(このコードはダウンロードファイル内のIntComparisonプロジェクトに入っています)。

C computing took 0.001971

 判断は読者にお任せします。ただし、このコードは速度の最適化を使ってコンパイルされていることを忘れないでください。

次のページ
インデックスメモリアドレッシング

この記事は参考になりましたか?

japan.internet.com翻訳記事連載記事一覧

もっと読む

この記事の著者

japan.internet.com(ジャパンインターネットコム)

japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.comEarthWeb.com からの最新記事を日本語に翻訳して掲載するとともに、日本独自のネットビジネス関連記事やレポートを配信。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

Liviu Tudor(Liviu Tudor)

英国在住のJavaコンサルタント。特にオンラインメディアセクタの高可用性システムに関して豊富な経験を持つ。Javaに長年取り組んでいるうちに、パフォーマンスが問題になるアプリケーションをうまく機能させるために必要なのは肥大したミドルウェアフレームワークではなく「低レベル」のコアJavaであると悟る。...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/4935 2010/03/08 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー