繁体   English   中英

Java strictfp 修饰符对现代 CPU 有什么影响吗?

[英]Does Java strictfp modifier have any effect on modern CPUs?

根据 JLS,我知道方法(和类)上的strictfp修饰符的含义:

JLS 8.4.3.5,strictfp 方法:

strictfp 修饰符的作用是使方法主体中的所有 float 或 double 表达式明确为 FP-strict(第 15.4 节)。

JLS 15.4 FP-strict 表达式:

在 FP-strict 表达式中,所有中间值必须是 float 值集或 double 值集的元素,这意味着所有 FP-strict 表达式的结果必须是 IEEE 754 算术对使用单双格式表示的操作数预测的结果.

在非 FP 严格的表达式中,为实现使用扩展的指数范围来表示中间结果提供了一些余地; 粗略地说,净效果是在独占使用浮点值集或双值集可能导致上溢或下溢的情况下,计算可能会产生“正确答案”。

我一直在试图想出一个办法让一个表达式之间的实际差异strictfp方法和一个不strictfp 我已经在两台笔记本电脑上尝试过这个,一台配备 Intel Core i3 CPU,另一台配备 Intel Core i7 CPU。 我看不出任何区别。

很多帖子表明,原生浮点数,不使用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 位。 查看movsdmulsddivsd 文档,他们都提到这些(SSE)指令对 64 位浮点值进行操作,而不是我预期的 80 位值。 因此,这些指令操作的双值集已经是 IEEE 754 值集似乎是合乎逻辑的,因此使用strictfp和不使用它之间没有区别。

我的问题是:

  1. 这个分析正确吗? 我不经常使用英特尔组装,所以我对我的结论没有信心。
  2. 是否有任何(其他)现代 CPU 架构(具有 JVM)在使用和不使用strictfp修饰符的操作之间存在差异?

如果“现代”是指处理器支持您在问题中引用的由编译器生成的 SSE2 指令( mulsd ,...),那么答案是否定的, strictfp没有区别,因为指令集没有允许利用没有strictfp优势。 可用的指令已经优化计算,以精确规格strictfp 换句话说,在这种现代 CPU 上,您始终可以以相同的价格获得strictfp语义。

如果“现代”是指历史上的 387 FPU,那么如果中间计算在strictfp模式下溢出或下溢,则可以观察到差异(不同之处在于它可能不会溢出,或者在下溢时保留比预期的)。

为 387 编译的典型strictfp计算看起来像这个答案中的程序集,通过精心选择的 2 次幂进行精心放置的乘法,以使下溢的行为与 IEEE 754 binary64 中的相同。 结果通过 64 位内存位置的往返会处理溢出。

在没有strictfp情况下编译的相同计算将在每个基本操作中产生一条387 条指令,例如对于源级乘法仅产生乘法指令fmulp (在程序开始时,387 将被配置为使用与 binary64 相同的有效位宽度,53 位。)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM