15

strictfpJLSによると、メソッド(およびクラス)の修飾子の意味を知っています:

JLS 8.4.3.5、strictfp メソッド:

strictfp 修飾子の効果は、メソッド本体内のすべての float または double 式を明示的に FP-strict にすることです (§15.4)。

JLS 15.4 FP 厳密な式:

FP 厳密式内では、すべての中間値は float 値セットまたは double 値セットの要素でなければなりません。これは、すべての FP 厳密式の結果が、single および double 形式を使用して表現されたオペランドに対する IEEE 754 演算によって予測されたものでなければならないことを意味します。 .

FP 厳密ではない式内では、実装が中間結果を表すために拡張指数範囲を使用するための余裕が認められます。大まかに言えば、実際の効果は、float 値セットまたは double 値セットを排他的に使用するとオーバーフローまたはアンダーフローが発生する可能性がある状況で、計算が「正しい答え」を生成する可能性があることです。

strictfpメソッド内の式とそうでない式の間の実際の違いを取得する方法を考え出そうとしていstrictfpます。Intel Core i3 CPU と Intel Core i7 CPU を搭載した 2 台のラップトップでこれを試しました。そして、私は違いを得ることができません。

多くの投稿は、 を使用しないネイティブ浮動strictfp小数点数が 80 ビット浮動小数点数を使用している可能性があり、可能な限り最小の Java double (ゼロに最も近い) よりも下、または可能な限り最大の 64 ビット Java double よりも上に余分な表現可能な数値があることを示唆しています。

以下のコードをstrictfp修飾子の有無にかかわらず試してみましたが、まったく同じ結果が得られました。

public static strictfp void withStrictFp() {
    double v = Double.MAX_VALUE;
    System.out.println(v * 1.0000001 / 1.0000001);
    v = Double.MIN_VALUE;
    System.out.println(v / 2 * 2);
}

実際には、コードがアセンブリにコンパイルされた場合にのみ違いが現れると想定しているため、-XcompJVM 引数を使用して実行しています。しかし違いはありません。

HotSpot によって生成されたアセンブリ コードを取得する方法を説明する別の投稿を見つけました ( OpenJDK ドキュメント)。でコードを実行していますjava -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly。修飾子を含む最初の式 ( v * 1.0000001 / 1.0000001) と、strictfp修飾子を含まない同じ式は、次のようにコンパイルされます。

  0x000000010f10a0a9: movsd  -0xb1(%rip),%xmm0        # 0x000000010f10a000
                                                ;   {section_word}
  0x000000010f10a0b1: mulsd  -0xb1(%rip),%xmm0        # 0x000000010f10a008
                                                ;   {section_word}
  0x000000010f10a0b9: divsd  -0xb1(%rip),%xmm0        # 0x000000010f10a010
                                                ;   {section_word}

そのコードには、私が予想していたように、各ステップの結果を 64 ビットに切り捨てるものは何もありません。、および ドキュメントを調べると、これらの (SSE) 命令は、予想した 80 ビット値ではなく、64 ビット浮動小数点値で動作することがすべて言及されています。したがって、これらの命令が動作する double 値セットがすでに IEEE 754 値セットであることは論理的に思われるため、それがある場合とない場合に違いはありません。movsdmulsddivsdstrictfp

私の質問は次のとおりです。

  1. この分析は正しいですか?私は Intel アセンブリをあまり使用しないので、結論に自信がありません。
  2. strictfp修飾子を使用する操作と使用しない操作に違いがある (他の) 最新の CPU アーキテクチャ (JVM を含む) はありますか?
4

1 に答える 1

11

「最新」とは、質問で引用した、コンパイラーによって生成された SSE2 命令の種類をサポートするプロセッサー ( mulsd、…) を意味する場合、答えはノーです。strictfp違いはありません。の不在を利用しstrictfpます。利用可能な命令は、 の正確な仕様を計算するためにすでに最適化されていstrictfpます。言い換えれば、そのような最新の CPU ではstrictfp、同じ価格で常にセマンティクスを取得できます。

「モダン」とは歴史的な 387 FPU を意味する場合、モードで中間計算がオーバーフローまたはアンダーフローするかどうかの違いを観察することができstrictfpます (違いは、オーバーフローしないか、アンダーフロー時に予想よりも多くの精度ビットを保持することです)。 )。

387 用にコンパイルされた典型的な計算は、この回答strictfpのアセンブリのようになり、適切に選択された 2 の累乗による乗算が適切に配置され、アンダーフローが IEEE 754 binary64 と同じように動作します。次に、64 ビットのメモリ ロケーションを介した結果のラウンドトリップにより、オーバーフローが処理されます。

なしでコンパイルされた同じ計算はstrictfp、基本操作ごとに 1 つの 387 命令を生成します。たとえばfmulp、ソースレベルの乗算の乗算命令だけです。(387 は、プログラムの開始時に、binary64、53 ビットと同じ有意桁幅を使用するように構成されていたはずです。)

于 2014-03-22T00:32:07.463 に答える