Nach dem Upgrade auf Java 1.8.0_20 hat unser Testsystem Fehler gemeldet, aber der Code wurde nicht geändert. Ich habe herausgefunden, dass Math.pow()
mit genau den gleichen Eingabeparametern unterschiedliche Ergebnisse bei veralteten Aufrufen liefert. In Java 1.8.0_11 verhält es sich wie erwartet und gibt immer den gleichen Wert zurück, aber mit Java 1.8.0_20 und höher gibt es manchmal etwas andere Werte zurück.Math.pow liefert bei wiederholten Aufrufen unterschiedliche Ergebnisse
Dies ist ähnlich der Frage Math.pow yields different result depending on java version, aber anders, weil die Ergebnisse von pow() innerhalb einer VM unterscheiden.
Der folgende JUint Test schlägt fehl, wenn unter Java 1.8.0_20 und höher
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 scheitert nicht unter Java 1.8.0_11 oder wenn der Hotspot mit -Xint
gedreht wird. Die strikte mathematische Version von pow() liefert konsistente Ergebnisse. Ich vermute, dass der Hotspot-JIT einige Optimierungen durchführt, die zu einer anderen Implementierung von pow() wechseln, was zu unterschiedlichen Ergebnissen für bestimmte Eingabewerte führt. Eine mathematische Funktion sollte deterministisch sein und konsistente und reproduzierbare Ergebnisse liefern.
Ist das ein Fehler oder eine Funktion?