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

Jos*_*erg 6 java floating-point strictfp java-17

JEP 306在 Java 17 中实现,提供始终严格的浮点语义,弃用该strictfp标志。这是否意味着java.lang.Math可以指望其行为与 中的类似方法完全相同StrictMath(即,该java.lang.Math方法不能再被 JVM 替换为过去所允许的内在函数)?这是否也意味着无论使用哪个库,不同架构之间的浮点数学结果不应再有任何差异?

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

Ser*_*nov 2

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

截至您的问题,OpenJDK 中有两个主要 PR 涉及 JEP 306 的更改

如果您查看第一个,尤其是StrictMath,您会发现它现在直接委托给j.l.Math,并且有关语义的注释strictfp现已删除(以及strictfpOpenJDK 代码库中的关键字)。此外,从 Java 17 开始,对关键字javac发出明确的警告(请参阅:strictfpcompiler.properties

从版本 17 开始,所有浮点表达式都经过严格计算,并且strictfp不是必需的

所以对于这个问题

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

答案是“是”,对于某些方法,例如Math.sinh(double)委托给StrictMath.sinh(double)(以及后来的FdLibm.Sinh.compute(dobule))和例如方法StrictMath.toRadians(double)委托给Math.toRadians(double)。最终,对于浮点变量,无论您是否调用Mathor的方法并不重要StrictMath,都会在幕后执行相同的代码。

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

即,java.lang.Math 方法不能再被 JVM 替换为过去所允许的内部函数

PR 不会对特定于平台并由 JVM 在运行时应用的内在函数强加任何更改,无论操作是否严格。此外,正如@Holger指出的那样,严格性和内在性之间并不矛盾。

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

答案是“从 Java 17 或更高版本开始是的”。在此之前,结果可能会有所不同,请参阅/sf/answers/1563457031/。在 Java 17 之前,如果对浮点变量的操作不严格,则标准假设:

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

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

聚苯乙烯

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

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