Math.pow在重复调用时产生不同的结果

Ada*_*dam 6 java math jvm-hotspot pow

升级到Java 1.8.0_20后,我们的测试系统报告错误,但代码没有更改.我发现,Math.pow()使用完全相同的输入参数调用会在重新调用的调用时产生不同的结果.在Java 1.8.0_11中,它的行为与预期的一样,并且总是返回相同的值,但是对于Java 1.8.0_20及更高版本,它有时会返回稍微不同的值.

这类似于Math.pow根据java版本产生不同结果的问题,但不同,因为pow()的结果在一个VM中不同.

在Java 1.8.0_20及更高版本下运行时,以下JUint测试失败

import static org.junit.Assert.assertEquals;

import java.util.function.BiFunction;

import org.junit.BeforeClass;
import org.junit.Test;

public class PowerTest {

    private static final int N = 1000000;
    private static final double base = 5350.456329377186;
    private static final double exp = 2.0;

    private static double eval(final BiFunction<Double, Double, Double> f) {
        return f.apply(base, exp);
    }

    private void loop(final BiFunction<Double, Double, Double> f) {
        final double x = eval(f);
        for (int i = 0; i < N; i++) {
            final double p = eval(f);
            assertEquals("i=" + i, x, p, 0);
        }
    }

    @BeforeClass
    public static void info() {
        System.out.println("Java " + System.getProperty("java.version"));
    }

    @Test
    public void mathPow() {
        loop(Math::pow);
    }

    @Test
    public void strictMathPow() {
        loop(StrictMath::pow);
    }
}
Run Code Online (Sandbox Code Playgroud)

在Java 1.8.0_11下测试不会失败,或者如果打开了热点,测试也不会失败-Xint.pow()的严格数学版本产生一致的结果.我怀疑热点JIT做了一些优化,切换到pow()的不同实现,这会产生某些输入值的不同结果.数学函数应该是确定性的,并且应该产生一致且可重复的结果.

这是一个错误还是一个功能?

NPE*_*NPE 8

我发现了以下错误报告:

JDK-7021568:Double.parseDouble()返回与体系结构相关的结果

它非常相似,因为它报告了一个浮点运算,在JITed代码与解释代码中返回的结果略有不同.

该问题被标记为错误并已修复.在此基础上,我认为你所看到的也是一个bug,应该报告给Oracle.