oma*_*eed 19 java floating-point precision jvm
在 2 个不同的 JVM(Java 8 和 Java 17)之间进行平均时,相同值存在差异的原因是什么?
是因为浮点吗?或者两个版本之间还有其他变化吗?
爪哇17
public class Main {
public static void main(String[] args) {
List<Double> amountList = List.of(27.19, 18.97, 6.44, 106.36);
System.out.println("JAVA 17 result: " + amountList.stream().mapToDouble(x -> x).average().orElseThrow());
}
}
Run Code Online (Sandbox Code Playgroud)
结果:39.739999999999995
爪哇8
public class Main {
public static void main(String[] args) {
List<Double> amountList = Arrays.asList(27.19, 18.97, 6.44, 106.36);
System.out.println("JAVA 8 result: " + amountList.stream().mapToDouble(x -> x).average().orElse(0.0));
}
}
Run Code Online (Sandbox Code Playgroud)
结果:39.74000000000001
Hol*_*ger 16
相关问题是JDK-8214761:并行 Kahan 求和实现中的错误
\n由于此错误报告中提到它DoubleSummaryStatistics也受到影响,因此我们可以构建一个消除所有其他影响的示例:
public class Main {\n public static void main(String[] args) {\n DoubleSummaryStatistics s = new DoubleSummaryStatistics();\n s.accept(27.19);\n s.accept(18.97);\n s.accept(6.44);\n s.accept(106.36);\n System.out.println(System.getProperty("java.version")+": "+s.getAverage());\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n我曾经生产过
\n1.8.0_162: 39.74000000000001\nRun Code Online (Sandbox Code Playgroud)\n17: 39.74000000000001\nRun Code Online (Sandbox Code Playgroud)\n(发行版本为Java\xc2\xa017)
\n和
\n17.0.2: 39.739999999999995\nRun Code Online (Sandbox Code Playgroud)\n它与修复程序的向后移植版本相匹配。
\n一般来说,该方法的约定表明结果不必与仅将值相加并除以大小的结果相匹配。\xe2\x80\x99s 的实现\xe2\x80\x99s 提供纠错的自由,但 \xe2\x80\x99s 也很重要,要记住浮点加法不是严格关联的,但我们必须将其视为关联能够支持并行处理。
\n我们甚至可以验证更改是否是一种改进:
\nDoubleSummaryStatistics s = new DoubleSummaryStatistics();\ns.accept(27.19);\ns.accept(18.97);\ns.accept(6.44);\ns.accept(106.36);\ndouble average = s.getAverage();\nSystem.out.println(System.getProperty("java.version") + ": " + average);\n\nBigDecimal d = new BigDecimal("27.19");\nd = d.add(new BigDecimal("18.97"));\nd = d.add(new BigDecimal("6.44"));\nd = d.add(new BigDecimal("106.36"));\n\nBigDecimal realAverage = d.divide(BigDecimal.valueOf(4), MathContext.UNLIMITED);\nSystem.out.println("actual: " + realAverage\n + ", error: " + realAverage.subtract(BigDecimal.valueOf(average)).abs());\nRun Code Online (Sandbox Code Playgroud)\n打印,例如
\n1.8.0_162: 39.74000000000001\nactual: 39.74, error: 1E-14\nRun Code Online (Sandbox Code Playgroud)\n17.0.2: 39.739999999999995\nactual: 39.74, error: 5E-15\nRun Code Online (Sandbox Code Playgroud)\n请注意,这是打印的十进制表示形式的错误。如果您想知道实际double表示与正确值的接近程度,则必须替换BigDecimal.valueOf(average)为new BigDecimal(average)。然后,误差之间的差异会稍微小一些,但是,新算法更接近两者的正确值。
| 归档时间: |
|
| 查看次数: |
508 次 |
| 最近记录: |