Matlab精度:简单减法不为零

时间:2011-10-27 15:43:17

标签: matlab floating-point precision

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

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

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

5 个答案:

答案 0 :(得分:4)

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提出的改进意见。改变以将差异的绝对值与阈值进行比较,而不是差异。

答案 1 :(得分: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. 中间结果也可能是精确结果的近似值。

答案 2 :(得分:1)

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

例如:

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

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

答案 3 :(得分:1)

您所看到的是quantization error。 Matlab使用双精度来表示数字,虽然它们具有很高的精度,但它们仍然不能代表所有实数,因为存在无数个实数。我不确定Aabaz的伎俩,但总的来说,我会说你没有什么可以做的,除了可能按摩你的输入是双重友好的数字。

答案 4 :(得分:1)

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

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

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

为了好玩,找出.1是二进制的......

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