Math.pow根据Java版本产生不同的结果
我在JDK版本1.7.0_60上运行以下代码:
System.out.println(Math.pow(1.5476348320352065, (0.3333333333333333)));
其结果是:1.1567055833133086
我在JDK版本1.7.0上运行完全相同的代码。
其结果是:1.1567055833133089
我明白,double不是无限精确的,但是java规范中的变化是否会导致差异?
PS:因为我们使用遗留系统,大十进制不是一个选项。
编辑:我能够追踪更改的时间:它是在JDK版本1.7.0_40中引入的(与版本1.7.0_25相比)。
但有没有在java规格导致差异的变化?
Math.pow
。 *根据Math.pow
的Javadocs,最多允许一个ULP(最后一个单位)的差异。 如果我们看看你的两个价值观:
System.out.printf("%016x\n", Double.doubleToLongBits(1.1567055833133086)); System.out.printf("%016x\n", Double.doubleToLongBits(1.1567055833133089));
我们得到:
3ff281ddb6b6e675 3ff281ddb6b6e676
这实际上相差一个ULP。
您所看到的可能是由于JDK / JVM用于实现这些操作的浮点指令序列略有不同。
*至less,我不知道!
规范没有改变,但热点优化器有一些变化可能与此相关。
我挖了这些代码部分:
- 从更新25: vm / opto / library_call.cpp:inline_pow
- 从更新40: vm / opto / library_call.cpp:inline_pow
(这些并不完全是引入这些更改的版本,因为您提供的版本信息,我只是select了它们)。
这些变化(以及代码在做什么)远远超出我可以在合理的时间内分析的结果,但也许有人认为这个参考很有趣或有用。
如果你想在JVM之间使用可重复的浮点值,你可以使用strictfp关键字,参见下面的问题什么时候应该在java中使用“strictfp”关键字?
为了在所有Java版本之间产生一致的结果,解决scheme是使用StrictMath.pow()
而不是Math.pow()
。
有关可能导致差异的背景信息,请参阅此答案 。