我在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:因为我们使用遗留系统,所以不能选择Big Decimal。
编辑:我能够追踪更改的时间:它是在JDK版本1.7.0_40中引入的(与版本1.7.0_25相比)。
答案 0 :(得分:41)
但是java规范中是否存在导致差异的变化?
否 * 根据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用于实现这些操作的浮点指令序列略有不同。
<小时/> *至少,据我所知!
答案 1 :(得分:8)
规范没有变化,但热点优化器中有一些变化,可能(!)与此相关。
我挖出了这些代码部分:
(这些不完全是引入这些更改的版本,我只是因为您提供的版本信息而选择它们)。
这些变化(以及代码所做的事情)远远超出了我在合理时间内可以分析的变化,但也许有人认为这个参考有趣或有用。
答案 2 :(得分:5)
如果您想在JVM之间使用可重复的浮点值,可以使用strictfp关键字,请参阅以下问题When should I use the "strictfp" keyword in java?
答案 3 :(得分:4)
为了在所有Java版本之间产生一致的结果,解决方案是使用StrictMath.pow()
而不是Math.pow()
。
有关可能导致差异的背景信息,请参阅this answer。