After upgrading to Java 1.8.0_20 our test system reported errors, but the code was not changed. I found out, that Math.pow()
called with exactly the same input parameters yields different results upon repreated calls. In Java 1.8.0_11 it behaves as expected and returns always the same value, but with Java 1.8.0_20 and above it sometimes returns slightly different values.
This is similar to the question Math.pow yields different result depending on java version, but different because the results of pow() differ within one VM.
The following JUint test fails when run under Java 1.8.0_20 and higher
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);
}
}
Test does not fail under Java 1.8.0_11 or if the hotspot is turned of with -Xint
. The strict math version of pow() yields consistent results. I suspect the hotspot JIT to do some optimizations that switch to a different implementation of pow(), which yields different results for certain input values. A mathematical function should be deterministic and should yield consistent and reproducible results.
Is this a bug or a feature?