浮动到Ints的精度与双打到Ints的精确度,出乎意料的结果

时间:2013-02-01 17:39:24

标签: c++ casting

我是计算机工程专业的学生,​​并为BYU-Idaho的入门C ++课程做辅导,一名学生成功地困扰了我。

如果为此编写代码:

#include <iostream>
using namespace std;
int main()
{
   float y = .59;
   int x = (int)(y * 100.0);
   cout << x << endl;
   return 0;
}

结果= 58

#include <iostream>
using namespace std;
int main()
{
   double y = .59;
   int x = (int)(y * 100.0);
   cout << x << endl;
   return 0;
}

结果= 59

我告诉他这是一个精确的问题,因为int比浮子更精确,它会丢失信息。双精度比浮点精确,所以它的工作原理。

但是我不确定我所说的是否正确。我认为这与使用零填充的int有关,因此当它被转换时会被“截断”,但我不确定。

如果你们中的任何一个人想要解释所有这些“下面”发生了什么,我会发现它很有趣!

4 个答案:

答案 0 :(得分:7)

问题是float不足以保持完全值0.59。如果存储这样的值,它将以二进制表示(已在编译期间)舍入为不同的值,在您的情况下,这是一个略小于0.59的值(它可能稍微大于您希望它的值) )。将此值乘以100时,得到的值略小于59.将此值转换为整数会将其向0 舍入,因此这将导致58。

0.59作为浮点数将被存储为(现在表示为人类可读的十进制数字):

0.589999973773956298828125

现在为double类型。虽然此类型具有基本相同的问题,但可能有两个原因可以获得预期结果:double可以保存您想要的完全值(0.59不是这种情况)但对于其他值(可能是这种情况),或者编译器决定将其向上。因此,将此值乘以100会导致小于59的值,并按预期将其舍入为0到59.

现在请注意,编译器仍然可以将0.59作为double向下舍入。的确,我刚刚检查过它。作为double的0.59将存储为:

0.58999999999999996891375531049561686813831329345703

但是,在将其转换为整数之前,您将此值乘以100 。现在有一个有趣的观点:当乘以100时,编译器放置的y与0.59的差值已消除,因为0.59 * 100可能无法再精确存储。实际上,处理器会计算0.58999999999999996891375531049561686813831329345703 * 100.0,它将向上舍入到59,这个数字可以double中表示!

有关详细信息,请参阅此代码:http://ideone.com/V0essb

现在你可能想知道为什么同样不计算float,它应该表现完全相同但精度不同。问题是0.589999973773956298828125 * 100.0 向上舍入为59(也可以在float中表示)。计算后的舍入行为并未真正定义。

实际上,对浮点数的操作并没有精确指定,这意味着您可以在不同的机器上遇到不同的结果。这样可以实现性能调整,导致稍微不正确的结果,即使不涉及舍入!情况可能是在另一台机器上你最终得到了预期的结果,而在其他机器上则不是。

答案 1 :(得分:2)

0.59在二进制浮点中不能完全表示。因此x实际上是一个略高于或低于0.59的值。您使用floatdouble可能会受到影响。这反过来将决定你的程序的结果是58还是59。

答案 2 :(得分:2)

这是一个精确的问题,与.59的事实有关 在doublefloat中无法准确表示。 因此y .59;它与.59非常接近 (略多或略少)。乘以100 确切地说,但由于原始价值不是,你会得到一些东西 略高于或略低于59。转换为int 截断为零,因此您可以获得5958

答案 3 :(得分:0)

这与使用旧计算器执行1 / 3 * 3时的问题相同,并且会出现2.9999999或类似内容。将此与(int)(float_value)将简单地删除小数的事实相结合,因此,如果floatvalue58.999996185,就像我的机器得到的那样,那么58将是结果,因为虽然58.999996185近59,如果你只剪出前两位,那确实是58.

浮点数非常适合计算很多东西,但在“结果是什么”时你必须非常小心。它是近似值,精度不是无限的,并且将发生中间结果的舍入。

使用double,有更多的数字,很可能是当计算0.58999999999999乘以100时,最后一位是1而不是0,所以结果是59.00000000001或类似的东西,然后变成59作为整数。