double average = LongStream
.of(-4480186093928204294L, -1340542863544260591L, -6004296286240039273L)
.average()
.getAsDouble()
This returns 2.20723960999901594E18 but I'm expecting it to return -3.9416750812375014E18 instead.
On the other hand, this returns a correct result (-1.4628605853333333E9):
double average = IntStream
.of(-1282256274, -1645263673, -1461061809)
.average()
.getAsDouble()
Why does IntStream.average() always return a correct average value and LongStream.average() sometimes doesn't?
The sum of the inputs exceeds the range of a long so the values wrap around to positive. (This is usually referred to as negative overflow. Usually underflow applies only to floating point, but it's started to come into usage to mean negative integer overflow.)
To fix, convert to double before computing the average:
double average = LongStream
.of(-4480186093928204294L, -1340542863544260591L, -6004296286240039273L)
.mapToDouble(x -> x)
.average()
.getAsDouble();
-3.9416750812375014E18
(update)
Overflow can also occur with IntStream, but it doesn't happen with the second example:
IntStream
.of(-1282256274, -1645263673, -1461061809)
.average()
The reason is that the intermediate values for the average operation on IntStream are converted to long variables. Even though summing these values as int will overflow, after conversion to long they won't. See the source code for IntPipeline.
Of course, if you provide enough int values in an IntStream, they will potentially overflow the intermediate long variables and you'll have the same problem.
You always have to watch out for overflow when dealing with large magnitudes or large numbers of integral values. There's no escaping it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With