为什么DoubleStream.sum()&#39的结果与直接添加不同?

时间:2017-09-11 11:32:39

标签: java

我很困惑。如果我算了

System.out.println(0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1);

然后我得到0.9999999999999999的结果。但是,如果我计算

Double sum = DoubleStream.builder().add(0.1).add(0.1).add(0.1).add(0.1).add(0.1).add(0.1).add(0.1).add(0.1).add(0.1).add(0.1).build().sum();
System.out.println(sum);

然后我得到1.0的结果。 为什么会有区别?

2 个答案:

答案 0 :(得分:10)

enter image description here 的Javadoc回答了您的问题:

  特别地,该方法可以使用补偿求和或其他技术来实现,以减少与双值的简单求和相比的数值和中的误差界限。

换句话说,sum()的实现不必使用双值的简单求和(可能会出现准确性问题,正如您在第一个代码段中所注意到的那样),因此可能会返回{ {3}}

编辑:请注意,尽管使用double' DoubleStream似乎可以提供更准确的结果,但这是一个实施细节,因此Javadoc无法保证。此外,简单的{{1}}添加更有效,因为它没有构建{{1}}的开销。您必须决定是否更倾向于更好的准确性或性能。

答案 1 :(得分:2)

只是为了增加Eran的答案,内部DoubleStream#sum使用Kahan Summation

相关部分:

/**
 * Incorporate a new double value using Kahan summation /
 * compensation summation.
 *
 * High-order bits of the sum are in intermediateSum[0], low-order
 * bits of the sum are in intermediateSum[1], any additional
 * elements are application-specific.
 *
 */
static double[] sumWithCompensation(double[] intermediateSum, double value) { ....