You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java并行求和与单线程求和存在精度差异的原因探究

并行计算数组倒数和的精度差异问题

我实现了继承自RecursiveAction的Sum类,用于计算数组元素的倒数之和(Σ1/a[i])。具体代码如下:

public class Sum extends RecursiveAction {
    int[] items;
    double result;
    int min = 100000;
    int from, to;

    Sum(int[] items, int from, int to) {
        this.items = items;
        this.from = from;
        this.to = to;
    }

    @Override
    protected void compute() {
        if (to - from <= min) {
            for (int i = from; i < to; i++) {
                result += 1d / items[i];
            }
        } else {
            var mid = (from + to) / 2;
            var left = new Sum(items, from, mid);
            var right = new Sum(items, mid, to);
            invokeAll(left, right);
            result += left.result + right.result;
        }
    }
}

运行后得到以下结果:

Single:   1.3180710500108106E8
Total time: 0.612
Parallel: 1.3180710501986596E8
Total time: 0.18 

可以看到单线程与并行计算的结果非常接近但存在微小精度差异,而若去掉倒数运算直接求和数组元素,结果则完全一致。请问这一差异的成因是什么?


精度差异的成因

  • 浮点数加法不满足结合律:这是问题的核心本质。单线程计算时,严格按照数组顺序依次累加每个倒数项;并行计算时,数组被拆分成多个子块独立累加,最后合并子块结果。由于二进制浮点数无法精确表示大多数小数,每个倒数项本身就是近似值,不同的累加顺序会让误差的累积路径不同,最终产生可观测的微小差异。
  • 倒数运算放大了精度敏感度:直接对int数组求和时,int类型值可以被double精确存储(double的53位有效位完全覆盖int的32位取值范围),每个求和项都是精确值。这种情况下,累加顺序带来的误差累积极低,在你的测试场景中表现为结果完全一致。但计算倒数后,1d / items[i]的结果几乎都是不精确的近似值,这些近似值在不同累加顺序下的误差叠加效应被放大,最终显现出差异。

内容的提问来源于stack exchange,提问作者GangYeah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 22:15:36