首页 > 解决方案 > Java 8 和 Java 13 中的 Math.pow() 返回不同的结果

问题描述

以下代码在 Java 8 和 Java 11 上返回不同的结果。

class Playground {
    public static void main(String[ ] args) {
        long x = 29218;
        long q = 4761432;
        double ret = Math.pow(1.0 + (double) x / q, 0.0005);
        System.out.println("val = " + String.format("%.24f", ret));
    }
}

爪哇 8:

val = 1.000003058823805400000000

Java 11:(与 Python、Rust 的结果相同)

val = 1.000003058823805100000000

这些问题是:

标签: javamathjvm

解决方案


如果我们只使用 Double.toString() 打印答案,那么两个不同的结果将是

1.0000030588238054
1.0000030588238051

末尾的额外数字只是 String.format() 的一个因素。我们看到这些数字仅在最后一个有效的十进制数字上有所不同。将这两个数字转换为十六进制给出

1.000033518c576
1.000033518c575

所以二进制表示在最后一位(ulp)仅相差一个单位。

阅读Math.pow的规范,我们发现

“计算结果必须在精确结果的 1 ulp 范围内。”

真实值接近 1.000003058823805246468 ( WolframAlpha ) 介于两个答案之间,因此两者都在规范范围内。

所发生的一切是该库在算法上略有改变,也许是为了让它更快。


推荐阅读