为什么IntStream.average()总是返回正确的结果,而LongStream.average()有时不会?

时间:2017-11-04 04:12:38

标签: java java-8 java-stream

double average = LongStream
   .of(-4480186093928204294L, -1340542863544260591L, -6004296286240039273L)
   .average()
   .getAsDouble()

这会返回2.20723960999901594E18,但我希望它会返回-3.9416750812375014E18

另一方面,这会返回正确的结果(-1.4628605853333333E9):

double average = IntStream
   .of(-1282256274, -1645263673, -1461061809)
   .average()
   .getAsDouble()

为什么IntStream.average()总是返回正确的平均值而LongStream.average()有时却没有?

2 个答案:

答案 0 :(得分:5)

输入的总和超出了long的范围,因此值会变为正值。 (这通常被称为负溢出。通常下溢仅适用于浮点,但它开始用于表示负整数溢出。)

要修复,请在计算平均值之前转换为double:

double average = LongStream
   .of(-4480186093928204294L, -1340542863544260591L, -6004296286240039273L)
   .mapToDouble(x -> x)
   .average()
   .getAsDouble();

-3.9416750812375014E18

(更新)

IntStream也会发生溢出,但第二个例子不会发生:

IntStream
    .of(-1282256274, -1645263673, -1461061809)
    .average()

原因是average上的IntStream操作的中间值会转换为long个变量。即使将这些值汇总为int也会溢出,但在转换为long之后,它们不会。请参阅source code for IntPipeline

当然,如果您在int中提供了足够的IntStream值,它们可能会溢出中间long个变量,并且您会遇到同样的问题。

在处理大量或大量积分值时,您始终需要注意溢出。没有逃脱它。

答案 1 :(得分:-1)

数字太长了,我们正在溢出:

System.out.println(-4480186093928204294L  -1340542863544260591L -6004296286240039273L);

6621718829997047458