与顺序无关的浮点求和[重复]

Posted

技术标签:

【中文标题】与顺序无关的浮点求和[重复]【英文标题】:Order-independent floating point summation [duplicate] 【发布时间】:2020-04-08 16:48:39 【问题描述】:

我知道浮点加法不是关联的:(a + b) + c 通常不等于a + (b + c)。所以这个求和算法可以根据输入的顺序给出不同的结果:

float naive_sum(float[] input) 
  float accumulator = 0;
  for (float x : input) 
    accumulator += x;
  
  return accumulator;

是否可以使这个顺序独立,以便即使输入被打乱也返回相同的结果?我不是想减少舍入误差:我只是希望它与订单无关。

一个想法是先对输入进行排序:

float sort_sum(float[] input) 
  return naive_sum(sort(input));

sort 不必将浮点数按数字顺序排列;它只需要满足sort(input) == sort(shuffle(input))。我认为这可行,但它不再像 naive_sum 那样是恒定的空间和线性时间。

另一个想法是让累加器成为一个巨大的整数类型:大到足以容纳任何浮点数而无需四舍五入。如果浮点数具有 11 位指数,则需要大约 2^11 位,即大约 2000 位。

float fixedpoint_sum(float[] input) 
  int2048 accumulator = 0;
  for (float x : input) 
    accumulator += float_to_fixed(x);
  
  return fixed_to_float(accumulator);

现在又是常数空间和线性时间,但是有这么大的累加器,可能是一个非常慢的线性时间。 :)

对于浮点数的顺序无关求和是否有任何实用算法?

【问题讨论】:

是否可以接受特定于 Java 的解决方案? 累加器方法可能没有你想象的那么糟糕:获取指数,用它索引累加器,加法,然后进位。进位偶尔会传播很多,但很少传播,除非应用程序设计中的某些东西导致它。然而,除了受累加器宽度限制之外,它并不是真正的恒定时间。也就是说,发生多少次进位会影响时间。但它通常很小。 【参考方案1】:

如果您的语言具有高精度的十进制类型,例如 Java 的 java.math.BigDecimal,请使用它来进行求和。从floatdoubleBigDecimal 的转换是精确的。如果您未指定需要舍入 BigDecimalMathContext,则添加也是精确的。最终的BigDecimal 值将是输入的实数和,实数加法是关联和交换的。唯一的舍入和舍入错误将在转换回float 时出现,无论输入顺序如何,都会转换相同的数字。

这类似于您的累加器想法,但利用了已经测试过的数据类型和限制“累加器”大小的内存管理。

private static float sum(float[] data) 
    BigDecimal adder = new BigDecimal(0);
    for(float f : data) 
        adder = adder.add(new BigDecimal(f));
    
    return adder.floatValue();

【讨论】:

【参考方案2】:

(a+b)+c 不等于 a+(b+c)”问题源于计算机无法以无限精度工作,它们在数学上并不精确;但他们使用某种丢失数字的表示形式。

阅读What Every Computer Scientist Should Know About Floating-Point Arithmetic了解详细说明。

这种表示具有粒度,这意味着两个连续表示之间的差异不是恒定的。小数不能加大数:1.1E20 + 1E-5 = 1.1E20

一些小的改进:

为了减少这个大大小小的问题,您可以对数字进行排序。所以 小值的总和可能会达到足够大的大小 值和加法可能更准确。还是没有 保证好结果。

另一种技术可能是以不同的顺序多次求和 (1,2,3... or 3,2,1... or 1,20,2,19,3,18... or...) 然后计算 所有总和的平均值。

最常用的(我相信)技术是扩大使用的位数。例如 64 位或 128 位而不是 32 位。或任意精度算术。价格为 128 位或更高的精度使计算速度变慢。

存在“鲁棒谓词”和this EGC site,它们试图将错误减少到最低限度,低于浮点/双小数。

【讨论】:

以上是关于与顺序无关的浮点求和[重复]的主要内容,如果未能解决你的问题,请参考以下文章

使用浮点 NumPy 数组进行比较和相关操作

查找与顺序无关紧要的嵌套数组的完全匹配

与 sys.path 顺序无关的与 SDK 包导入同名的 python 站点包

2个坐标的快速散列顺序无关紧要?

web.xml 中的listener filterservlet 加载顺序

Java:如何以相反的顺序对浮点数组进行排序?