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

Zhe*_*lov 2 java java-8 java-stream

double average = LongStream
   .of(-4480186093928204294L, -1340542863544260591L, -6004296286240039273L)
   .average()
   .getAsDouble()
Run Code Online (Sandbox Code Playgroud)

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

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

double average = IntStream
   .of(-1282256274, -1645263673, -1461061809)
   .average()
   .getAsDouble()
Run Code Online (Sandbox Code Playgroud)

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

Stu*_*rks 5

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

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

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

-3.9416750812375014E18
Run Code Online (Sandbox Code Playgroud)

(更新)

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

IntStream
    .of(-1282256274, -1645263673, -1461061809)
    .average()
Run Code Online (Sandbox Code Playgroud)

原因是average操作的中间值IntStream被转换为long变量.即使将这些值相加int也会溢出,转换后long它们也不会.请参阅IntPipeline源代码.

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

在处理大量或大量积分值时,您总是需要注意溢出.没有逃脱它.

  • @ZhekaKozlov哦.你编辑了这个问题.也许这就是你被投票的原因.(我没有投票.) (2认同)