Math.pow根据java版本产生不同的结果

时间:2014-08-20 11:56:33

标签: java math floating-point pow

我在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相比)。

4 个答案:

答案 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