代码之家  ›  专栏  ›  技术社区  ›  splicer

把大量的小浮点数加到一起的好方法是什么?

  •  10
  • splicer  · 技术社区  · 16 年前

    假设一个数组中有100000000个32位浮点值,每个浮点值的值都在0.0到1.0之间。如果你想把它们都总结成这样

    result = 0.0;
    for (i = 0; i < 100000000; i++) {
        result += array[i];
    }
    

    你会遇到麻烦的 result

    那么,有哪些方法可以更准确地进行求和呢?

    5 回复  |  直到 14 年前
        1
  •  30
  •   Community Mohan Dere    6 年前

    听起来你想用 Kahan Summation .

    Kahan求和算法 补偿求和 )与明显的方法相比,通过添加一个有限精度的浮点数序列,大大减少了数值总误差。这是通过保持一个单独的运行补偿(一个积累小误差的变量)来实现的。

    在伪码中,算法是:

    function kahanSum(input)
     var sum = input[1]
     var c = 0.0          //A running compensation for lost low-order bits.
     for i = 2 to input.length
      y = input[i] - c    //So far, so good: c is zero.
      t = sum + y         //Alas, sum is big, y small, so low-order digits of y are lost.
      c = (t - sum) - y   //(t - sum) recovers the high-order part of y; subtracting y recovers -(low part of y)
      sum = t             //Algebraically, c should always be zero. Beware eagerly optimising compilers!
     next i               //Next time around, the lost low part will be added to y in a fresh attempt.
    return sum
    
        2
  •  1
  •   i_am_jorf    16 年前

        3
  •  1
  •   Rex Kerr    16 年前

    float temp = new float[1000000];
    float temp2 = new float[1000];
    float sum = 0.0f;
    for (i=0 ; i<1000000000 ; i++) temp[i/1000] += array[i];
    for (i=0 ; i<1000000 ; i++) temp2[i/1000] += temp[i];
    for (i=0 ; i<1000 ; i++) sum += temp2[i];
    

    但在做这些之前,我们可能只是将结果累加成一个双精度。那会很有帮助的。

        4
  •  0
  •   Rob Packwood    16 年前

    如果在.NET中使用IEnumerable上存在的LINQ.Sum()扩展方法。那就是:

    var result = array.Sum();
    
        5
  •  0
  •   jkff    16 年前

    绝对最佳的方法是使用优先级队列,如下所示:

    PriorityQueue<Float> q = new PriorityQueue<Float>();
    for(float x : list) q.add(x);
    while(q.size() > 1) q.add(q.pop() + q.pop());
    return q.pop();
    

    (此代码假定数字为正数;一般来说,队列应该按绝对值排序)

    说明:给出一个数字列表,为了尽可能精确地相加,你应该努力使数字接近,t.i.消除小数字和大数字之间的差异。这就是为什么要将两个最小的数字相加,从而增加列表的最小值,减少列表中最小值和最大值之间的差异,并将问题大小减少1。

    不幸的是,考虑到您使用的是OpenCL,我不知道如何将其矢量化。但我几乎可以肯定这是可以的。你可能会看一看关于向量算法的书,令人惊讶的是它们实际上有多么强大: Vector Models for Data-Parallel Computing