2

double の乗算と BigDecimal のパフォーマンスをテストする簡単なベンチマークを作成しました。私の方法は正しいですか?コンパイラーが乗算定数を何度も最適化したため、ランダム化された値を使用します (例: Math.PI * Math.E)。
しかし:
- テスト内で乱数を生成すると結果が壊れるかどうかはわかりません。
- テスト内で新しいBigDecimalオブジェクトを作成する場合も同様です。

乗算のみのパフォーマンスをテストしたい (コンストラクターが使用する時間ではない)。

どうすればそれができますか?

import java.math.*;
import java.util.*;

public class DoubleVsBigDecimal
{
    public static void main(String[] args)
    {
        Random rnd = new Random();
        long t1, t2, t3;
        double t;

        t1 = System.nanoTime();

        for(int i=0; i<1000000; i++)
        {
            double d1 = rnd.nextDouble();
            double d2 = rnd.nextDouble();
            t = d1 * d2;
        }

        t2 = System.nanoTime();

        for(int i=0; i<1000000; i++)
        {
            BigDecimal bd1 = BigDecimal.valueOf(rnd.nextDouble());
            BigDecimal bd2 = BigDecimal.valueOf(rnd.nextDouble());
            bd1.multiply(bd2);
        }

        t3 = System.nanoTime();

        System.out.println(String.format("%f",(t2-t1)/1e9));
        System.out.println(String.format("%f",(t3-t2)/1e9));
        System.out.println(String.format("%f",(double)(t3-t2)/(double)(t2-t1)));
    }
}
4

4 に答える 4

3

Javaでのベンチマークは本当に奇妙です。 たとえば、JVMは、コードが何度も実行されるまで実際には完全に最適化されませんが、本番システムではこのメソッドが何度も呼び出されるため、最適化後に測定を行う方が公平です。

Javaベンチマークには他にもたくさんの落とし穴があります。おそらく、それらを回避する最も簡単な方法は、 Caliperなどの専門家によって構築されたJavaベンチマークツールを使用することです。

于 2012-05-22T19:21:52.250 に答える
3

乗算操作のタイミングを計るだけでなく、他のタイミングも計ります。

次のようなことをする必要があります。

    long time = 0; 
    for(int i=0; i<1000000; i++) {
        double d1 = rnd.nextDouble();
        double d2 = rnd.nextDouble();
        long start = System.nanoTime();
        t = d1 * d2;
        long end = System.nanoTime();
        time += (end-start)
    }
    long meantime = time / 1000000;

次に、おそらく標準誤差も計算します。また、開始する前に、最初にいくつかの計算でjvmをウォームアップする必要があります。そうしないと、開始時にいくつかの高い値が取得されます。

于 2012-05-22T19:15:32.383 に答える
1

ベンチマークの入門として、次の記事を強くお勧めします。

http://www.ibm.com/developerworks/java/library/j-benchmark1/index.html

于 2012-05-22T20:08:27.963 に答える
1

前もって 1000 個の double/BigDecimals の 2 つのコレクションを生成し、2 つのネストされたループでそれぞれを乗算できます。

public static void main(String[] args)
{
    Random rnd = new Random();
    List <Double> dl = new ArrayList <Double> ();
    List <BigDecimal> bdl = new ArrayList <BigDecimal> ();

    for(int i=0; i<1000; i++)
    {
        double d = rnd.nextDouble();
        dl.add (d);
        bdl.add (new BigDecimal (d));
    }

    long t1 = System.nanoTime();
    double t;
    for (double d1 : dl)
            for (double d2 : dl)
                t = d1 * d2;

    long t2 = System.nanoTime();

    for (BigDecimal b1 : bdl)
        for (BigDecimal b2 : bdl)
                b1.multiply (b2);

    long t3 = System.nanoTime();

    System.out.println (String.format ("%f", (t2 - t1) / 1e9));
    System.out.println (String.format ("%f", (t3 - t2) / 1e9));
    System.out.println (String.format ("%f", (double) (t3 - t2) / (double) (t2 - t1)));
} 

最初のコードは、繰り返されると、次のような非常に安定した値を生成しました。

0,186755
10,970243
58,741445

そして、私のコードはこの異なる値ですが、安定しています:

0,077177
1,112490
14,414710

関係の違いは 1:4 で、かなりのものです。リレーション BigDecimal:double ほどではありませんが、まあ ---

(i386-32、クライアント モード、JRE-1.6、linux、oracle、2Ghz Centrino シングル コア)。

于 2012-05-22T19:43:45.180 に答える