升級到Java 1.8.0_20後,我們的測試系統報告了錯誤,但代碼沒有更改。我發現,使用完全相同的輸入參數調用Math.pow()
可以在重新調用時產生不同的結果。在Java 1.8.0_11中,它的行爲與預期相同,並且返回的值始終相同,但對於Java 1.8.0_20及更高版本,它有時會返回稍微不同的值。Math.pow在重複調用時會得到不同的結果
這與問題Math.pow yields different result depending on java version類似,但不同,因爲pow()的結果在一個VM內不同。當的Java 1.8.0_20下運行和更高的
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沒有的Java 1.8.0_11下可能會失敗,或者如果熱點與-Xint
打開的
以下JUint測試失敗。 pow()的嚴格數學版本會產生一致的結果。我懷疑熱點JIT做了一些優化,切換到pow()的不同實現,對某些輸入值產生不同的結果。數學函數應該是確定性的,並且應該產生一致和可重複的結果。
這是錯誤還是功能?