gre*_*reg 5 java precision jit java-8 java-17
在用 Java 实现的科学计算管道的背景下,我们使用 Apache Commons math 3.6.1 中的 LeastSquare 优化器,并体验到 Java 8 (jdk8u322-b06)、Java 和 Java 17 之间奇怪的数值差异。
我们注意到迁移到 Java 17(当前使用 17.0.5)后的差异。
我可以在“简单”单元测试中重现 Java 8 和 Java 17 之间的不同行为,而无需涉及完整的计算管道,因此排除了数据加载或多线程部分可能出现的所有问题。
在 JDK 17 中,严格的浮点语义已恢复,但结果与编译或解释的 Java 8 完全不同。在这种情况下,实际上最小二乘优化器不会像在 Java 8 情况下那样收敛。
重要的一点是,所有这些结果都可以完全重现到最后一位数字,并且在每个平台配置上都是完全可预测的。
但这次在完整的管道执行中,我观察到我可以在 Java 8 本身上重现数值差异,具体取决于代码是解释还是编译(在 C2 级别或 C1 级别我尚未调查)
我真的很困惑,想知道这是否是已知/记录的行为,或者这是否是 JDK 8 平台或 JDK 17 中的错误?有人观察到这样的问题吗?
感谢您的任何提示!
编辑
我无法在这里提供简单的代码片段来重现该问题。但我提取了代码的必要部分以在 GitHub 存储库中重现该行为。免责声明:我不是代码的原作者。
重现步骤:
要查看行为差异,只需将 pom.xml 中的 java.version 属性从 1.8 切换到 17。
我可以查明 Apache math commons 中代码分歧的位置:在 Apache Math commons 3.6.1 的 LevenbergMarquardtOptimizer 类中(第 453 行)
double actRed = -1.0;
if (0.1 * currentCost < previousCost) {
double r = currentCost / previousCost;
actRed = 1.0 - r * r;
}
Run Code Online (Sandbox Code Playgroud)
在迭代 17 时,actRed 变为 0,因为在 Java 17 中 r==1,而在 Java 8 中则稍微为正,因为值为 0,稍后(第 533 行)抛出非收敛异常
if (FastMath.abs(actRed) <= TWO_EPS &&
preRed <= TWO_EPS && ratio <= 2.0) {
throw new ConvergenceException(LocalizedFormats.TOO_SMALL_COST_RELATIVE_TOLERANCE,
costRelativeTolerance);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
119 次 |
| 最近记录: |