如何检测浮点加法和乘法舍入导致的精度损失?

How can I detect lost of precision due to rounding in both floating point addition and multiplication?

来自计算机系统:程序员的视角:

With single-precision floating point

  • the expression (3.14f+1e10f)-1e10f evaluates to 0.0: the value 3.14 is lost due to rounding.

  • the expression (1e20f*1e20f)*1e-20f evaluates to +∞ , while 1e20f*(1e20f*1e-20f) evaluates to 1e20f.

谢谢。

虽然在数学中,实数的加法和乘法是关联运算,但这些运算在对浮点类型执行时 不是 关联的,例如 float,由于有限的精度和范围扩展。

所以顺序很重要。

考虑到示例,数字 10000000003.14 不能精确表示为 32 位 float,因此 (3.14f + 1e10f) 的结果将是 等于 1e10f,这是最接近的可表示数字。当然,3.14f + (1e10f - 1e10f) 会变成 3.14f

请注意,我使用了 f 后缀,因为在 C 中,表达式 (3.14+1e10)-1e10 涉及 double 文字,因此结果确实是 3.14(或更多可能类似于 3.14999).

在第二个例子中发生了类似的事情,其中​​1e20f * 1e20f已经超出了float的范围(但不是double)并且连续乘法没有意义,而(1e20f * 1e-20f),它首先在另一个表达式中执行,具有明确定义的结果 (1),连续乘法得出正确答案。

在实践中,有一些注意事项你采取

  • 使用更宽的字体。 double 最适合大多数应用程序,除非有其他要求。
  • 如果可能,重新排序操作。例如,如果您必须添加许多项并且您 知道 其中一些比其他项小,请先添加这些项,然后再添加其他项。避免相同数量级的数字相减。一般来说,可能有一种比原始方法更准确的代数表达式求值方法(例如霍纳的多项式求值方法)。
  • 如果您对问题领域有某种了解,您可能已经知道计算的哪一部分可能有问题值,并在执行计算之前检查这些值是否大于(或小于)某些限制。
  • 尽快查看结果。当你已经有一个无穷大的值或 NaN 时,继续计算是没有意义的,或者当你的目标值根本没有被修改时继续迭代。