【问题标题】:Why does IntStream.average() always return correct result while LongStream.average() sometimes doesn't?为什么 IntStream.average() 总是返回正确的结果,而 LongStream.average() 有时不会?
【发布时间】:2018-04-16 20:47:18
【问题描述】:
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() 有时不返回?

【问题讨论】:

  • IntStream 行为正常,因为总和被转换为double,因为返回了OptionalDouble。如果不超过Double.MAX_VALUE/Double.MIN_VALUE,您将不会溢出/下溢。
  • @JacobG。在LongStream 中,总和也被转换为double
  • 虽然没有明确说明。注意double n = -6004296286240039273L; 编译;不需要演员表。
  • @JacobG 我认为你完全没有抓住重点。这与从 int 到 double 的转换(和双精度)无关。这是关于为总和值的累积选择正确的类型。

标签: java java-8 java-stream


【解决方案1】:

数字太大了,我们快溢出了:

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

6621718829997047458

【讨论】:

    【解决方案2】:

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

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

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

    (更新)

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

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

    原因是averageIntStream 操作的中间值被转换为long 变量。即使将这些值求和为int 会溢出,但在转换为long 后它们不会溢出。请参阅source code for IntPipeline

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

    在处理大数值或大量整数值时,您总是需要注意溢出。逃不掉的。

    【讨论】:

    • 我知道溢出。我更好奇为什么 IntStream.average() 和 LongStream.average() 行为不同。
    • @ZhekaKozlov 哦。您编辑了问题。也许这就是你被否决的原因。 (我没有投反对票。)
    • 我认为这是相当不幸的,我应该永远记得添加mapToDouble :(
    • @ZhekaKozlov 只需使用DoubleStream
    • 因此,他们牺牲了正确性来换取性能。处理长溢出会花费太多。
    猜你喜欢
    • 2021-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多