浮点减法返回不正确的值

时间:2011-03-10 16:44:20

标签: c++

所以我有一个计算,其中减去了两个作为向量对象组件的浮点数,然后似乎返回了错误的结果。

我试图使用的代码是:

cout << xresult.x << " " << vec1.x << endl;
float xpart1 = xresult.x - vec1.x;
cout << xpart1 << endl;

运行此代码的位置将返回

16 17
-1.00002

正如您所看到的,打印出xresult.x和vec1.x的值分别告诉您它们分别为16和17,但减法操作似乎会引入错误。

任何想法为什么?

8 个答案:

答案 0 :(得分:4)

  

正如你所看到的,打印出来的   xresult.x和vec1.x的值告诉我们   你是16岁和17岁   分别,还有减法   操作似乎引入了一个错误。

不,它根本没有告诉我们。它告诉我们输入值大约是16和17.通常,不精确可能来自两个来源:浮点表示的性质,以及打印数字的精度。

输出流将浮点值打印到一定的精度。来自std::setprecision函数的描述:

  

在默认浮点上   符号,精度字段   指定的最大数量   有意义的数字总计显示   计算那些之前和那些   小数点后。

因此,xresult.xvec1.x的值为16和17 ,精确度为5位小数。实际上,一个略小于16而另一个略大于17.(请注意,这与不精确的浮点表示无关。声明float f = 16float g = 17都指定了精确值。 float可以保存精确的整数16和17(尽管有float无法容纳的无数多个其他整数。))当我们略微超过17时,从略微减去 - 16,我们得到的答案略大于负-1。

为了向自己证明这是事实,请进行这些实验中的一个或两个。首先,在您自己的代码中,在打印这些值之前添加“cout&lt;&lt; std :: setprecision(10)”。其次,运行此测试程序

#include <iostream> 
#include <iomanip>

int main() {
  for(int i = 0; i < 10; i++) {
    std::cout << std::setprecision(i) <<
      15.99999f << " - " << 17.00001f << " = " <<
      15.99999f - 17.00001f << "\n";
  }
}

注意输出的第7行与你的情况如何匹配:

16 - 17 = -1.00002

P.S。关于不精确浮点表示的所有其他建议都是有效的,它不适用于您的特定情况。你真的应该读“每个计算机科学家应该知道的关于浮点运算的东西”。

答案 1 :(得分:3)

这是因为浮点数如何运作。 http://en.wikipedia.org/wiki/Floating_point

答案 2 :(得分:2)

这称为浮点运算。这就是数字代码如此“棘手”并充满陷阱的原因。结果是预料之中的。而且,它可能取决于您正在使用的处理器,以及您将看到它的程度和程度。

我想补充说浮点变量的每种类型的变量:float,double,long double都有不同的精度因子。也就是说,人们可能更能够更准确地表示浮点数的值。这可以通过这些数字如何保存在记忆中来证明。

当您查看浮点数时,它包含的有效数字少于双倍或长倍数。因此,当您对它们执行数字时,您必须预期浮动将遭受更大的舍入误差。在处理财务数据时,开发人员经常使用一些“十进制”的外观。这些更好的设计用于处理货币类型操作,具有更高的有效数字精度。但它有一个价格。

查看IEEE 745-2008规范。

答案 3 :(得分:1)

因为您无法使用浮点数准确表示所有数字。维基百科对它有一个很好的描述:http://en.wikipedia.org/wiki/Floating_point

答案 4 :(得分:0)

如果16和17上有一个小的小数部分未打印出来,当值被归一化到相同的减法基数时,可能会引入额外的错误,特别是对于像{{1}这样的32位类型}。

当您使用浮点值时,您需要在应用程序中做好准备,以处理您不会获得100%准确的十进制结果的事实。您的结果将在内部二进制表示中尽可能准确。加法和减法尤其会为相距数量级的操作数引入大量的相对误差,并且结果应接近0。

答案 5 :(得分:0)

您对数字存储在计算机中的方式了解多少?

此外,xresult.x和vec1.x是什么 - 就像它们的内部等或浮动一样。

我会感到惊讶的是,如果它们都是浮点数,则会发生错误,但是您在类型之间进行转换,而二进制文件与十进制数字不同。

答案 6 :(得分:0)

让你的变量加倍而不是浮点数。你会得到更多精确度。

修改 计算机使用一系列位来存储数字。存储的位越多,结果的精度越高。实际上浮点数通常具有一半的位数作为双精度,因此它们具有较低的精度。

答案 7 :(得分:0)

人们一直在谈论计算机表示如何不能完美地表示实数,以及计算机对浮点数的操作如何不能完全精确。

这是事实,但现实世界也是如此。

实际测量值是某种程度精度的近似值。对实际测量的操作会产生一定程度的精确度。

如果算上17个保龄球,我有17个保龄球。如果我取出16个保龄球,我会有一个保龄球。

但如果我有一根17英寸长的棍子,我真正拥有的是一根约17英寸长的棍子。如果我切断16英寸,我真的切断了大约16英寸,而我剩下的大约是1英寸。

您必须跟踪测量的准确性以及结果的精确度。如果我有17.0,精确到三位有效数字,并减去16.0,也精确到三位有效数字,结果是1.0,精确到两位有效数字。这就是你得到的。你的错误在于假设你的结果提供的额外精度超出你给出的准确度是有意义的。不是。这是毫无意义的噪音。

这不是特定于计算机浮点数的东西,无论是使用计算器还是手工解决问题都会遇到同样的问题。

跟踪您的有效数字,并格式化您的答案以抑制超出重要性的精确度。