【问题标题】:Java 8 stream: periodic sum on arrayJava 8流:数组上的周期性求和
【发布时间】:2016-02-12 10:41:19
【问题描述】:

我想对数组进行周期性求和,即对索引模 n 求和。

int size=100;
double[] doubleArr = new double[size];
for (int i = 0; i < size; i++){
    doubleArr[i]=Math.random();
}
int n=2;
double[] results= new double[n];
for (int i = 0; i < doubleArr.length; i++) {
    results[i % n] += doubleArr[i];
}
System.out.println(Arrays.toString(results));

此代码有效,但由于我的数组非常庞大,我想并行化操作。

Java 8 流似乎是一个很好的解决方案。

double[] results2= new double[n];
IntStream.range(0, doubleArr.length).forEach(i -> results2[i % n] += doubleArr[i]);
System.out.println(Arrays.toString(results2));

我得到相同的结果。很好。

但如果我想要并行化,它会失败。

double[] results3= new double[n];
IntStream.range(0, doubleArr.length).parallel().forEach(i ->     results3[i % n] += doubleArr[i]);
System.out.println(Arrays.toString(results3));

我明白这是因为 results3 是可变的。

我想我应该在流操作中产生结果,用一个收集,但我不知道如何继续。

【问题讨论】:

  • 它因异常而失败或如何?如果抛出异常,则发布异常,如果结果不是预期的,则发布结果和期望
  • “失败”是什么意思?
  • @REACHUS 最终数组是从多个线程编辑的,结果不准确
  • 对,结果不准确,例如结果 [21.860094470094793, 21.53562534144981] 结果2 [21.860094470094793, 21.53562534144981] 结果3 [21.69682132149239, 20.755094007057508]

标签: java arrays indexing sum java-stream


【解决方案1】:

您可以从可能的模数范围 (0..n) 开始:

double[] result = IntStream.range(0, n)
         .mapToDouble(i -> IntStream.rangeClosed(0, (size-i-1)/n)
                                    .mapToDouble(j -> doubleArr[j*n+i]).sum())
         .toArray();

如果n 比您拥有的内核数量多,那么并行外部流就足够了。如果没有,请尝试并行化内部流。

【讨论】:

  • 但它比基本循环慢:'(
  • @xehyrofidd,与size = 1_000_000 并行,它对我来说更快(尽管加速不是很重要)。顺便说一句,如果您不需要 Kahan 求和,请将 .sum() 替换为 .reduce(0, Double::sum),它会更快。
  • 是的,与大小相比,n 的小值更快。但在 n=size/50 的情况下,它不再是了。
  • @xehyrofidd,你也很可能不正确地测量速度。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-10
  • 1970-01-01
  • 1970-01-01
  • 2018-03-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多