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

标签: algorithm floating-point non-deterministic


【解决方案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,它们试图将错误减少到最低限度,低于浮点/双小数。

    【讨论】:

      猜你喜欢
      • 2020-12-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-27
      • 1970-01-01
      • 1970-01-01
      • 2019-08-29
      • 2022-01-15
      相关资源
      最近更新 更多