【问题标题】:C thinking : float vs. integers and float representationC 思维:浮点数与整数和浮点数表示
【发布时间】:2017-11-16 17:11:02
【问题描述】:

在 C(以及许多其他语言)中使用整数时,除法时必须注意精度。在除法之前,乘法和加法总是更好的(这样会产生更大的中间结果,只要它不溢出)。

但是花车呢?这还成立吗?或者它们是否以这样一种方式表示:将相似数量级的数量而不是大数量级除以小数量级更好?

【问题讨论】:

  • 首先您需要了解浮点数在内存中的表示方式,请参阅this answer(来自软件工程)
  • 在使用整数时必须注意精度是什么意思?如果你对一个整数进行除法,那么你使用的是整数除法,所有结果的精度都是第 0 位小数。从这个意义上说,整数除法是精确的。
  • 在进行浮点运算时将舍入误差保持在最低限度是一个相当大的话题。作为一个简单的规则,最好是操作数具有相似的大小。例如:将一个小的浮点值添加到一个巨大的浮点值中,根本不会改变巨大的值(前提是两者之间的差异足够大)。
  • 是的,但是在大多数情况下,当您实现时,您使用整数除法作为您想要执行的理想除法的退化版本,并且简单地忍受没有小数部分出现的事实。然而,如果你改变单位,你的结果就会改变......例如,你以米为单位工作,然后将 10 米除以 4 得到 2,但如果你切换到毫米,10 000 除以 4 变成 2500,这是一个更好的结果......
  • @4386427 是的,添加(或减去)不同大小的数字会导致精度损失(当添加许多类似大小的数字时,这是一个真正的问题,例如求平均值),但是相乘(或划分)不同数量级的数字并不是那么糟糕。

标签: c floating-point integer division integer-division


【解决方案1】:

浮点数/双精度数和类似浮点工作的表示,旨在保留有效数字的数量(也称为“精度”),而不是固定数字小数位,例如发生在定点或整数工作中。

最好避免组合数量,这可能会导致指数下隐含或溢出,即在浮点数范围的限制。

因此,应避免加/减量级差异很大的量(明确地,或由于具有相反的符号)),并在可能的情况下重新安排,以避免这种众所周知的失去精度的途径。

示例:最好重构/重新排序

small + big + small + big + small * big

作为

(small+small+small) + big + big

因为小人物可能对大人物没有任何影响,因此他们的贡献可能会消失。

如果任何数量的低位存在任何“噪音”或不精确,了解有效位的丢失如何通过计算传播也是明智的。

【讨论】:

    【解决方案2】:

    (对于整数)在除法之前乘以加总是更好(这样会产生更大的中间结果,只要它不溢出)。

    这仍然成立吗(对于浮动)?

    一般来说,答案是否

    很容易构建一个例子,在除法之前添加所有输入会产生巨大的舍入误差。

    假设您要添加 10000000000 个值并将它们除以 1000。进一步假设每个值都是 1。所以预期结果是 10000000。

    方法一 但是,如果您在除法之前添加所有值,您将得到结果 16777.216(对于 32 位浮点数)。正如你所看到的,它几乎没有了。

    方法二 那么在将每个值添加到结果之前将其除以 1000 会更好吗?如果这样做,您将得到结果 32768.0(对于 32 位浮点数)。正如你所看到的,它也差不多了。

    方法三 但是,如果您继续添加值直到临时结果大于 1000000,然后将临时结果除以 1000,然后将该中间结果添加到最终结果并重复此操作,直到您添加了总共 10000000000 个值,您将得到正确的结果。

    所以在处理浮点数时,没有简单的“在除法之前总是加法”或“在加法之前总是先除法”。作为一般规则,将操作数保持在相似的大小通常是一个好主意。这就是第三个示例的作用。

    【讨论】:

      【解决方案3】:

      使用整数:
      只要没有溢出,+,-,* 总是准确的。
      使用除法时,结果会被截断,并且通常不等于数学答案。
      ia,ib,ic,在除法之前乘以 ia*ib/ic 与 ia*(ib/ic) 更好,因为商基于乘积 ia*ib 的更多位而不是ib.

      带浮点:
      问题很微妙。同样,只要没有上溢/下溢,顺序或*,/ 序列的影响小于整数。 FP */- 类似于添加/减去日志。典型结果与数学正确答案相差 0.5 ULP。

      对于 FP 和 +,-,当 1) 值在幅度上相差很远或 2) 减去几乎相等的值并且现在先前计算中的错误时,fa,fb,fc 的结果可能与数学正确的结果有显着差异变得重要。

      考虑二次方程:

      double d = sqrt(b*b - 4*a/c);  // assume b*b - 4*a/c >= 0
      double root1 = (-b + d)/(2*a);
      double root2 = (-b - d)/(2*a);
      

      对比

      double d = sqrt(b*b - 4*a/c);  // assume b*b - 4*a/c >= 0
      double root1 = (b < 0) ? (-b + d)/(2*a)  :  (-b - d)/(2*a)
      double root2 = c/(a*root1);  // assume a*root1 != 0
      

      当一个根接近 0 并且 |b| 接近 d 时,第二个具有更好的 root2 精度结果。这是因为b,d 减法取消了许多重要位,从而使d 的计算中的错误变得重要。


      【讨论】:

        猜你喜欢
        • 2011-01-04
        • 1970-01-01
        • 2011-04-19
        • 1970-01-01
        • 2017-07-26
        • 2011-01-10
        • 1970-01-01
        • 2016-06-01
        • 1970-01-01
        相关资源
        最近更新 更多