如何检测由于浮点加法和乘法舍入而导致的精度损失? [已关闭]

问题描述 投票:0回答:1

从计算机系统:程序员的角度:

单精度浮点

  • 表达式

    (3.14f+1e10f)-1e10f
    的计算结果为 0.0:值 3.14 由于舍入而丢失。

  • 表达式

    (1e20f*1e20f)*1e-20f
    的计算结果为 +∞ ,而
    1e20f*(1e20f*1e-20f)
    的计算结果为
    1e20f

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

  • 下溢和我描述的问题有什么联系和区别?下溢是否只是由于舍入而导致精度损失的一种特殊情况,即结果舍入为零?

c floating-point rounding numerical-methods underflow
1个回答
1
投票

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

float

所以顺序很重要。

考虑到这些示例,数字 10000000003.14 无法精确表示为 32 位

float
,因此
(3.14f + 1e10f)
的结果将是 equal
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 时,继续计算是没有意义的,或者当你的目标值根本没有修改时继续迭代是没有意义的。
© www.soinside.com 2019 - 2024. All rights reserved.