Java 17和JEP 306之后Math和StrictMath之间还有区别吗?

问题描述 投票:0回答:1

JEP 306,在 Java 17 中实现,提供始终严格的浮点语义,弃用 strictfp

 标志。这是否意味着 
java.lang.Math
 可以指望与 
StrictMath
 中的类似方法完全相同(即 
java.lang.Math
 方法不能再被 JVM 替换为过去允许的内在函数)?这是否也意味着无论使用哪个库,不同架构之间的浮点数学结果不应再有任何差异?

我很好奇我是否误解了新的 Java 17 功能,因为我们确实看到 Apple Silicon 与 Intel 之间今天的代码存在差异。

java floating-point java-17 strictfp
1个回答
0
投票
首先,

strictfp

不是一个标志,这是一个Java关键字,确保在对浮点变量(
float
double
)进行运算时在每个平台上具有相同的计算结果。

就您的问题而言,OpenJDK 中有两个主要 PR 涉及 JEP 306 的更改

  • 8244146:JEP 306 的 javac 更改
  • 8266530:JEP 306 的热点更改
如果您查看第一个,尤其是

StrictMath,您会发现它现在直接委托给 j.l.Math

,并且有关 
strictfp
 语义的注释现已删除(以及 OpenJDK 代码库中的 
strictfp
 关键字)。
此外,从 Java 17 开始 
javac
strictfp
 关键字发出明确的警告(参见 
compiler.properties
:

从版本 17 开始,

所有浮点表达式都经过严格计算,并且 strictfp

 不是必需的

所以对于这个问题

这是否意味着 java.lang.Math 的行为可以与 StrictMath 中的类似方法完全相同

对于某些方法,例如,答案是“是”

Math.sinh(double)

 委托给 
StrictMath.sinh(double)
(然后再委托给 
FdLibm.Sinh.compute(dobule)
),例如方法 
StrictMath.toRadians(double)
 委托给 
Math.toRadians(double)
。最终,对于浮点变量,无论您调用 
Math
 还是 
StrictMath
 的方法并不重要,相同的代码都会在后台执行。

截至同一问题的这一部分:

也就是说,java.lang.Math 方法不能再被 JVM 替换为以前允许的内部函数

PR 不会对特定于平台并由 JVM 在运行时应用的内在函数强加任何更改,无论操作是否严格。而且,正如

@Holger指出的那样,严格性和内在性之间并不矛盾。

这是否也意味着无论使用哪个库,不同架构之间的浮点数学结果不应再有任何差异?

答案是“从 Java 17 或更高版本开始是的”。在此之前,结果可能会有所不同,请参阅

https://stackoverflow.com/a/22335100/12473843。在 Java 17 之前,如果对浮点变量的操作不严格,标准会假设

在单独使用浮点值集或双精度值集可能导致上溢或下溢的情况下,计算可能会产生“正确答案”。 但目前语义总是严格的,您在所有平台上都会得到相同的结果。

另请参阅

8268224:清理核心库注释中对“strictfp”的引用

附注

我们确实看到 Apple Silicon 与 Intel 之间今天的代码存在差异

我认为编译器为不同平台生成不同的代码是很自然的,这里的问题是您是否在上述平台上看到不同的计算结果。

© www.soinside.com 2019 - 2024. All rights reserved.