5

パフォーマンスが非常に重要な状況にあります。double私のアルゴリズムの中核には、2 つのプリミティブを使用していくつかの基本的な計算を行うメソッドがあります。このメソッドは、アルゴリズムの実行ごとに 1,000 万回以上呼び出されます。

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

public int compare(double xA, double xB, double yA, double yB);

    double x = xA * xB;
    double y = yA * yB;

    double diff = x - y;

    return (diff < 0.0 ? -1 : (diff > 0.0 ? 1 : 0));

}

パラメータxAyAセットから値を取得します。このセットは、コードで微調整できます。セットに入れる値によって、大きな (約 2 倍の) パフォーマンスの違いが見られます。セットに a0.1または aが含まれている0.3と、パフォーマンスが大幅に低下するようです。セットを の倍数にしておくと0.5、最高のパフォーマンスが得られます。

コンパイラはなどとして最適化x * 0.5していx >> 1ますか? それとも0.1バイナリで定義できないからですか?

これを最適化できるように、この状況をもう少しよく理解したいと思います。javac と jvm (この場合はホットスポット) が二重乗算を処理する方法を正確に知っている人がいない限り、これは非常に難しい問題になると思います。

4

1 に答える 1

1

ちょうどカップルいくつかのアイデア:

  • 値が 0.5 の倍数である場合、数に有効なビットがほとんどないため、乗算のサイクル数が少なくて済むようです。最近のプロセッサは double に 2 サイクルしかかからないため、乗算の実際の有効ビットは問題ではないようです (浮動小数点除算と浮動小数点乗算で説明されているように)。

    たとえば、 0.5 、 1 、 2、 4 などの場合、仮数部はすべてゼロになると考えています (最初の「1」は暗黙的であるため省略されています)。.75、1.5、3 などの場合、msb の「1」の後にすべてゼロが続きます。一方、0.1 では、すべての有効桁数の精度を使用して表現されますが、それでも小さなエラーが発生します。

  • 返された結果について: Math.signum()に問題はありますか? つまり、これは同じことをするかもしれません:

    return Math.signum(x-y);
    
  • 精度が重要でない場合は、単精度 (float) の使用を検討してください。(ただし、それが double から前後に変換することを意味する場合、それは価値がないかもしれません)。

于 2012-08-01T12:10:18.513 に答える