【问题标题】:Matlab precision: simple subtraction is not zeroMatlab精度:简单减法不为零
【发布时间】:2011-10-27 15:43:17
【问题描述】:

我在 Matlab 上计算这个简单的总和:

2*0.04-0.5*0.4^2 = -1.387778780781446e-017

但结果不为零。我能做些什么?

【问题讨论】:

标签: matlab floating-point precision


【解决方案1】:

Aabaz 和 Jim Clay 对发生的事情有很好的解释。

通常情况下,您真正​​想要的是检查 2*0.04 和 0.5*0.4^2 是否相差很小,而不是精确计算 2*0.04 - 0.5*0.4^2 的值足以在相关的数值精度范围内。如果是这种情况,与其检查是否为2*0.04 - 0.5*0.4^2 == 0,不如检查是否为abs(2*0.04 - 0.5*0.4^2) < thresh。这里的thresh 可以是任意小的数字,也可以是涉及eps 的表达式,它给出了您正在使用的数字类型的精度。

编辑: 感谢 Jim 和 Tal 提出的改进建议。更改为将差值的绝对值与阈值进行比较,而不是差值。

【讨论】:

  • 好点。我要做的一个改变是您需要将差异的绝对值与“thresh”进行比较。
【解决方案2】:

Matlab 使用双精度浮点数来存储实数。这些是m*2^e 形式的数字,其中m2^522^53尾数)之间的整数,e 是指数。如果一个数字是这种形式,我们就称它为浮点数。

计算中使用的所有数字都必须是浮点数。通常,这可以完全做到,就像在你的表达式中使用20.5。但对于其他数字,尤其是大多数小数点后有数字的数字,这是不可能的,必须使用近似值。在这种情况下,数字会四舍五入到最接近的浮点数。

所以,每当你在 Matlab 中写 0.04 之类的东西时,你实际上是在说“给我最接近 0.04 的浮点数。在你的表达式中,有2 个需要近似的数字:0.040.4

此外,浮点数的加法和乘法等运算的确切结果可能不是浮点数。虽然它总是采用m*2^e 的形式,但尾数可能太大。因此,四舍五入运算结果会导致额外的错误。

在一天结束时,像您这样的简单表达式的操作数大小将相差大约 2^-52 倍,或大约 10^-17。

总而言之:您的表达式计算结果不为零的原因有两个:

  1. 您开始使用的某些数字与您提供的确切数字不同(近似值)。
  2. 中间结果也可能是精确结果的近似值。

【讨论】:

    【解决方案3】:

    您看到的是quantization error。 Matlab 使用双精度数来表示数字,虽然它们具有很高的精度,但它们仍然不能表示所有实数,因为实数的数量是无限的。我不确定 Aabaz 的把戏,但总的来说,我会说你无能为力,除了可能将你的输入按摩成双友好数字。

    【讨论】:

      【解决方案4】:

      我不知道它是否适用于您的问题,但通常最简单的解决方案是扩展您的数据。

      例如:

      a=0.04;
      b=0.2;
      a-0.2*b
      ans=-6.9389e-018
      c=a/min(abs([a b]));
      d=b/min(abs([a b]));
      c-0.2*d
      ans=0
      

      编辑:当然我并不是要对这类问题给出一个通用的解决方案,但它仍然是一个很好的做法,可以让你避免一些数值计算中的问题(曲线拟合, ETC ...)。请参阅 Jim Clay 的回答,了解您遇到这些问题的原因。

      【讨论】:

      • 老实说我不知道​​,但解决这类问题肯定是朝着正确的方向发展。
      • 这是否有原因,还是只是临时代码在这种情况下碰巧做了“正确”的事情?
      • 这并不总是有效的,可以通过尝试f = @(x)1-x/x^2*x 然后f(rand()) 几次来看到。有时是 0;其他时候是epsilon。缩放可以帮助您获得更好的结果,但准确度仍在 epsilon 范围内。另一种选择是缩放 epsilon 以匹配问题中其他值的比例。
      【解决方案5】:

      我很确定这是一个古老的浮点精度问题。

      您需要 1e-17 精度吗?这仅仅是想要“漂亮”输出的情况吗? 在这种情况下,您可以只使用格式化的 sprintf 来显示您想要的有效位数。

      意识到这不是一个 matlab 问题,而是数字如何以二进制表示的基本限制。

      为了好玩,计算一下二进制中的 .1 是什么...

      一些参考资料: http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems http://www.mathworks.com/support/tech-notes/1100/1108.html

      【讨论】:

        猜你喜欢
        • 2014-12-15
        • 1970-01-01
        • 2016-05-26
        • 2023-03-29
        • 2017-07-07
        • 2018-04-11
        • 1970-01-01
        • 2011-07-30
        • 1970-01-01
        相关资源
        最近更新 更多