【问题标题】:How do you correctly calculate a running average of large sets of numbers with 32-bit floating point?您如何正确计算具有 32 位浮点数的大型数字集的运行平均值?
【发布时间】:2011-09-09 12:30:57
【问题描述】:

我正在编写一个路径跟踪器,并且必须收集每个像素的大量样本的平均值。我在 1024 个样本运行和 16384 个样本运行之间得到了显着的视觉差异; 16384 个样本运行较暗。我猜这是因为 16384 样本图像遇到浮点精度错误。我通过将每个值除以 16384 来平均颜色值,然后将它们加在一起。

有没有一种方法可以对已知量级的大量难以计算的数字集进行平均,同时最大限度地减少舍入误差?最好不需要非常量内存,绝对不丢弃任何样本?

【问题讨论】:

  • 正确浮点?我很好奇这是否比明显的“不相容概念”更有趣。
  • 我正在使用浮点数,因为我试图在聚合器数组上节省内存(是的,数组中有很多浮点数,至少我非常努力地保留在 L2 中)。问题不在于获得正确,而是如何获得最佳准确度。
  • 一个显而易见的实验是在测试运行中切换到双打。如果它不能使变暗消失,那么它一开始就不太可能是精度问题。
  • 聚合器数组?您所要做的就是将它们添加到一个比您用于存储样本的类型大得多的变量(“变量”,单数)中。要避免使用几个额外的字节,你会遇到很多麻烦。
  • 聚合器数组,因为我分批计算光线。 :-)

标签: math floating-point average


【解决方案1】:

您可能想要Kahan summation algorithm。当使用有限精度浮点运算对大量点求和时,这是一种将累积舍入误差最小化的简单有效的方法。

【讨论】:

  • 但是由于空间原因 OP 已经在使用单精度浮点数,切换到双精度浮点数将比单精度 Kahan 提供更好的精度,而且工作量要少得多。 Kahan 的算法本质上是使用一个双寄存器累加器来将有效位的数量加倍——但双精度的原生尾数已经是单精度的两倍多(因为指数只表示一次)。
  • Kahan 非常适合,因为碰巧我的结果数组中有一个 vec3f,但我目前并未实际使用(发射色和反射色)。所以没关系。 (另一种方法是使用联合,这有点难看)
【解决方案2】:

由于您要除以 2 的幂,并且您的数字不是极小,因此这一步应该不会对结果的准确性产生任何影响。你只是从指数中减去 14。

重要的是样本中的位数。

浮点数为您提供 24 位精度。如果您有 2^14 = 16384 个样本,那么当您将它们全部加起来时,您将逐渐失去精度,直到在第 24-14=10 位丢失后的某个时刻。换句话说:此时您只保留大约 3 位小数。

是否可以使用 int 作为累加器,甚至是 uint?这样,您将保留 8 个额外位,是 1024 和 16384 样本之间差异的两倍。

还有第二种完全不同的选择。我不知道您的样本的范围是多少,但如果它们的大小大致相同,您可以从每个值中减去一个近似平均值,平均差异,然后在最后加上近似平均值。

您通过这种方法获得多少取决于您对平均值的初始近似值有多好,以及这些值与平均值的接近程度。所以我想说在你的情况下它可能不太可靠。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-07
    • 1970-01-01
    • 2021-08-05
    相关资源
    最近更新 更多