当前位置: 首页 > 面试题库 >

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

齐起运
2023-03-14
问题内容

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

JLS
8.4.3.5,strictfp方法:

strictfp修饰符的作用是使方法体内的所有float或double表达式都显式受FP-strict约束(第15.4节)。

JLS 15.4 FP-
strict表达式:

在FP-strict表达式中,所有中间值都必须是浮点值集或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);
}

实际上,我假设只有在将代码编译为程序集时才会显示任何差异,因此我将使用-XcompJVM参数运行它。但是没有区别。

我找到了另一篇文章,解释了如何获取由HotSpot生成的汇编代码(OpenJDK文档)。我正在使用运行我的代码java -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssemblyv * 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位。仰望
文件的movsdmulsd并且divsd,他们都提到,这些(SSE)指令对64位浮点值进行操作,而不是80位的值,如我所料。因此,这些指令所操作的双精度值集已经是IEEE
754值集,这似乎合乎逻辑,因此拥有strictfp和不拥有它之间没有区别。

我的问题是:

  1. 这种分析正确吗?我不经常使用英特尔汇编程序,因此我对自己的结论不满意。
  2. 是否有(其他)现代CPU体系结构(具有JVM),对于使用或不使用strictfp修饰符的操作,它们之间是否有区别?

问题答案:

如果用“现代”来表示处理器支持您在问题中引用的由编译器生成的SSE2指令mulsd,…),则答案是否定的,strictfp没有任何区别,因为指令集不允许利用的缺席strictfp。可用的指令已经可以最佳地计算出的精确规格strictfp。换句话说,在这种现代CPU上,您strictfp始终以相同的价格获得语义。

如果用“现代”表示历史性的387
FPU,则有可能观察到中间计算是否会在strictfp模式下溢出或下溢(差异在于它可能不会溢出或在下溢时保留比预期更多的精度位) )。

strictfp为387编译的典型计算看起来像是此答案中的程序集,其中乘以适当选择的2的幂进行适当的乘法运算以使下溢的行为与IEEE
754 binary64中的相同。结果通过64位存储器位置的往返处理可以解决溢出问题。

如果不进行编译,则相同的计算strictfp将为每个基本操作生成387条指令,例如,仅fmulp针对源级乘法的乘法指令。(在程序开始时,将387配置为使用与binary64
53位相同的有效宽度。)



 类似资料:
  • private private修饰符是我们使用的最限制的修饰符。它表示它只能被自己所在的文件可见。所以如果我们给一个类声明为private,我们就不能在定义这个类之外的文件中使用它。 另一方面,如果我们在一个类里面使用了private修饰符,那访问权限就被限制在这个类里面了。甚至是继承这个类的子类也不能使用它。 所以一等公民,类、对象、接口……(也就是包成员)如果被定义为private,那么它们只

  • 问题内容: 如何为未装饰的jframe添加阴影? 从我在网上找到的内容中,您也许可以将jframe添加到另一个黑色 半透明窗口中以产生阴影效果。或者以某种方式将 这样的内容应用于JFrame: 我只是想知道最好的方法,或者是完全不同的 方法来获得相同的效果,例如从另一个类而不是从 jframe扩展。我是Java的新手,所以我可能走错了方向,因此欢迎您提出任何 建议。 问题答案: 基本上,您需要制作

  • 主要内容:VB.Net修饰符列表修饰符是添加了任何编程元素的关键字,以特别强调编程元素在程序中的行为或将被访问 例如,访问修饰符:, , , , 等指示编程元素的访问级别,如:变量,常量,枚举或类。 VB.Net修饰符列表 下表提供了VB.Net修饰符的完整列表: 编号 修饰符 描述 1 指定Visual Basic应将所有字符串封送到美国国家标准学会(ANSI)值,而不管正在声明的外部过程的名称如何。 2 指定源文件开始处的属

  • .lazy 在默认情况下,v-model在每次input事件触发后将输入框的值与数据进行同步 (除了上述输入法组合文字时)。你可以添加lazy修饰符,从而转变为使用change事件进行同步: <!-- 在“change”时而非“input”时更新 --> <input v-model.lazy="msg" > .number 如果想自动将用户的输入值转为数值类型,可以给v-model添加num

  • 修饰符是添加了任何编程元素的关键字,以特别强调编程元素在程序中的行为或将被访问的方式。 例如,访问修饰符:Public,Private,Protected,Friend,Protected Friend等,表示编程元素的访问级别,如变量,常量,枚举或类。 VB.Net中的可用修饰符列表 下表提供了VB.Net修饰符的完整列表 - Sr.No 修改 描述 1 Ansi 指定Visual Basic应

  • 主要内容:final 修饰变量,final修饰方法,final修饰类,final 修饰符使用总结final 在 Java 中的意思是最终,也可以称为完结器,表示对象是最终形态的,不可改变的意思。final 应用于类、方法和变量时意义是不同的,但本质是一样的,都表示不可改变,类似 C# 里的 sealed 关键字。 使用 final 关键字声明类、变量和方法需要注意以下几点: final 用在变量的前面表示变量的值不可以改变,此时该变量可以被称为常量。 final 用在方法的前面表示方法不可以