Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does DoubleStream.sum()'s result differ from straight addition?

Tags:

java

I am confused. If I calculate

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

Then I get a result of 0.9999999999999999. But if I calculate

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);

Then I get a result of 1.0. Why is there a difference?

like image 946
J. Doe9891 Avatar asked Sep 11 '17 11:09

J. Doe9891


2 Answers

The Javadoc of double java.util.stream.DoubleStream.sum() answers your question:

In particular, this method may be implemented using compensated summation or other technique to reduce the error bound in the numerical sum compared to a simple summation of double values.

In other words, the implementation of sum() doesn't have to use simple summation of double values (which can have accuracy issues, as you noticed in your first snippet), and therefore may return a more accurate result.

EDIT: Note that even though using DoubleStream's sum() appears to give a more accurate result, this is an implementation detail, so it's not guaranteed by the Javadoc. Besides, simple double addition is more efficient, since it doesn't have the overhead of constructing a DoubleStream. You have to decide if you prefer potential better accuracy or performance.

like image 193
Eran Avatar answered Nov 09 '22 07:11

Eran


Just to augment Eran's answer, internally DoubleStream#sum uses Kahan Summation.

Relevant parts:

/**
 * 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) { ....
like image 23
Eugene Avatar answered Nov 09 '22 07:11

Eugene