提问人:Joshua Goldberg 提问时间:7/13/2023 更新时间:7/13/2023 访问量:90
在 Java 17 和 JEP 306 之后,Math 和 StrictMath 之间还有区别吗?
Is there still a difference between Math and StrictMath after Java 17 and JEP 306?
问:
在 Java 17 中实现的 JEP 306 提供了始终严格的浮点语义,弃用了该标志。这是否意味着 java.lang.Math 的行为与 StrictMath 中的类似方法完全相同(即,java.lang.Math 方法不能再像过去允许的那样被具有内部函数的 JVM 替换)?这是否也意味着,无论使用哪个库,不同架构之间的浮点数学结果都不应再有任何差异?strictfp
我很好奇我是否误解了 Java 17 的新特性,因为我们确实看到了 Apple Silicon 与 Intel 之间在当今代码中的差异。
答:
首先,它不是一个标志,这是一个 Java 关键字,用于确保在对浮点变量 ( 和 ) 进行运算时在每个平台上获得相同的计算结果。strictfp
float
double
就您的问题而言,OpenJDK 中有两个主要的 PR 涉及 JEP 306 的更改
如果你看一下第一个,特别是 StrictMath,你会看到它现在直接委托给,并且关于语义的注释现在被删除了(以及 OpenJDK 代码库中的关键字)。
此外,从 Java 17 开始,对关键字发出明确的警告(参见:j.l.Math
strictfp
strictfp
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 之间在当今代码中的差异
我认为编译器为不同的平台生成不同的代码是很自然的,这里的问题是你是否在上述平台上看到不同的计算结果。
评论
上一个:Java 浮点格式化和舍入
下一个:浮点数学坏了吗?
评论
java.lang.Math