strictfp
JLSによると、メソッド(およびクラス)の修飾子の意味を知っています:
strictfp 修飾子の効果は、メソッド本体内のすべての float または double 式を明示的に FP-strict にすることです (§15.4)。
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);
}
実際には、コードがアセンブリにコンパイルされた場合にのみ違いが現れると想定しているため、-Xcomp
JVM 引数を使用して実行しています。しかし違いはありません。
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 値セットであることは論理的に思われるため、それがある場合とない場合に違いはありません。movsd
mulsd
divsd
strictfp
私の質問は次のとおりです。
- この分析は正しいですか?私は Intel アセンブリをあまり使用しないので、結論に自信がありません。
strictfp
修飾子を使用する操作と使用しない操作に違いがある (他の) 最新の CPU アーキテクチャ (JVM を含む) はありますか?