浮動小数点ならどうなるか
整数演算について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つの例で調べてみましょう。
ifステートメントで2つの整数を使用する。このifステートメントでは、ステートメントが真の場合は、単純な割り当てを実行する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
判断は読者にお任せします。ただし、このコードは速度の最適化を使ってコンパイルされていることを忘れないでください。
