【问题标题】:What is the risk of numerical instabilities when predividing denominators?预除分母时数值不稳定的风险是什么?
【发布时间】:2015-04-01 12:03:27
【问题描述】:

假设我想将一个数字分成多个。

a /= x;
b /= x;
c /= x;
...

由于乘法更快,所以很容易这样做

tmp = 1.0f / x;
a *= tmp;
b *= tmp;
c *= tmp;
...

1) 这能保证产生相同的答案吗?我怀疑不是,但一些确认会很好。

2) 如果x 非常大或非常小,我预计这可能会导致准确性显着下降。有没有一个公式可以告诉我我会牺牲多少准确度?

3) 也许没有方便的公式,但我们至少可以说明一个经验法则,说明数值不稳定性何时会成为问题?是与操作数的大小有关,还是与操作数的大小之间的差异有关?

【问题讨论】:

  • 不同指数的乘除法不会造成比平时更多的损失。然而,指数相差较大的加减法确实会造成很大的损失或精度。

标签: c floating-point numeric ieee-754


【解决方案1】:

1) 不,不能保证产生相同的答案。即使使用 IEEE,通过使用 a/xa*(1/x),细微的舍入效果也可能导致 1 或 2 ULP

2) 如果x 非常小(即比DBL_MIN(最小归一化正浮点数)小一点,如在次法线的情况下),则1/x 的总数为INF精度损失。当 FP 模型不支持次法线时,x 非常大时也会出现潜在的显着精度损失。
通过针对最大的有限数<= 1/DBL_MIN 和最小的非零数>= 1/DBL_MAX 测试|x|,代码可以确定何时开始出现严重的准确性损失。公式可能取决于使用的 FP 模型和x 的指数以及模型的限制。在这个binary64 的范围内,xEmin(或Emax)的二进制指数之差将是丢失比特的一阶估计值。

3) 在上述范围内会出现明显的数值不稳定性。

【讨论】:

  • 考虑有限double 数字的范围,让我们假设x > 0.0通常最大有限值DBL_MAXDBL_MIN(最小归一化正浮点数)适当地相互取反。由于它们可能很容易不是彼此的精确数学逆,因此其中一个或另一个将具有可表示的逆,而另一个则没有。这就是问题的开始。
  • 大多数 FP 也使用次法线,因此数字范围是 DBL_MAXDBL_TRUE_MIN(最小正浮点数),而这 2 的倒数揭示了问题的另一个位置继续 - 通常在范围的高端。
  • @spraff BTW:喜欢你的照片 - 我们是在同一家商店订购的吗?
  • 可表示逆等的评论。人。很有趣。
【解决方案2】:

以下是一些带有支持链接的想法:

1) - 产生相同的结果?没有保证。对可变性的贡献太多,从 uP 设计(还记得 486 DX 数学协处理器的 math co-processor design error 吗?)到编译器实现,再到float 存储在硬件内存中。 (Good discussion on that here.)

2) - 公式?我不知道一个。而且,重大错误是什么意思?在任何情况下,您都可以通过以下方式确定您将看到的精度:

  • 了解 various implementations 浮点数(链接比较 2)
  • 使用什么变量类型(floatdoublelong double)。 (differences)
  • 您在构建什么架构 32 位还是 64 位,其他?

关于浮点错误的讨论很多。 Here is one

3)没有真正的经验法则(如果经验法则你的意思是容易请记住,易于应用,易于理解)但是,这里是 a good attempt 回答有关浮点错误的问题

【讨论】:

    【解决方案3】:

    当您使用 ieee-754 数字时,我会说您的方法是完全可以接受的。在ieee-754中x大致是

    尾数 * 2 指数

    其中尾数是 1/2 和 1 之间的数字。

    所以只要你只做乘除法,你当然会有精度损失,但这种损失与x(*)的大小无关,只与浮点类型的精度有关已使用(单精度、四精度的双精度,这意味着 floatdoublelong double,具体取决于编译器和架构)。

    (*) 仅当您不会出现下溢溢出时才是正确的,即单精度约为 1038,双精度约为 10300

    参考:维基百科上的页面 Floating pointIEEE floating point

    【讨论】:

      【解决方案4】:

      我的 50 美分:

      1) 不,在 3 中进一步解释。

      2)我不知道任何公式,所以我将跳过这个。

      3) 我知道的经验法则是尽量只在数量级接近的操作数之间执行操作。

      实际示例:

      您想将数字 63.000.000 除以 1.000.000。

      使用第一种方法,您最终会将 63*10^6 划分为 1*10^6,它们的数量级非常接近。

      但是,如果您要使用第二种方法,那么

      temp = 1.0f / x;
      

      将产生 10^(-6)。

      现在,乘以 63*10^6 * 10^(-6) 将导致显着的精度损失,因为两者之间的量级差异很大。 CPU会尝试用10^6数的指数+小数表示来表示10^(-6)数...

      一个可行的替代方案是将 temp 设为

      temp = 1 / 1.000;
      

      然后

      a = a * temp * temp ;
      

      因为量级越接近,精度损失的可能性就越小。

      【讨论】:

      • 不,这不会导致精度损失。如果操作数都不是非正规的,则有效数总是非常接近。指数可以很容易地调整。只有幅度差异很大的加减法通常是有问题的。
      • @Rudy Velthius 你是对的。我将修改我的答案并使操作数 denromal。我猜想使用 10 的幂来强调精度损失让我展示了一个事情实际上很容易处理的案例。
      猜你喜欢
      • 2011-07-20
      • 2011-03-14
      • 2010-12-30
      • 2018-09-11
      • 2011-12-30
      • 2010-11-19
      • 2017-06-17
      • 2020-08-22
      • 1970-01-01
      相关资源
      最近更新 更多