4

我是计算机工程专业的学生,​​为 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 比 float 更精确,它会丢失信息。double 比 float 更精确,因此可以工作。

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

如果你们中的任何一个人想解释这一切“下面”发生的事情,我会觉得这很有趣!

4

4 回答 4

7

问题是它float不够准确,无法保持精确值 0.59。如果您存储这样的值,它将以二进制表示形式(已经在编译期间)四舍五入到不同的值,在您的情况下,这是一个略小于 0.59 的值(它也可能略大于您想要的值)。将其与 100 相乘时,您会得到一个略小于 59 的值。将这样的值转换为整数会将其舍入为 0,因此得到 58。

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

0.589999973773956298828125

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

现在请注意,double编译器可能仍将 0.59 作为 a 进行四舍五入。确实,我刚刚检查过,确实如此。0.59 作为 adouble将存储为:

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也可以用 a 表示float)。计算后的舍入行为并未真正定义。

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

于 2013-02-01T17:44:06.493 回答
2

0.59 不能完全用二进制浮点表示。所以x实际上是一个略高于或低于 0.59 的值。它可能会受到您是否使用float或的影响double。这反过来将确定您的程序的结果是 58 还是 59。

于 2013-02-01T17:42:26.990 回答
2

这是一个精度问题,并且与在 a或 a.59 中都不能完全表示的事实有关。所以不是;_ 它非常接近 (略多或略少)。乘以 是精确的,但由于原始值不是,所以你得到的东西比 略多或略少。转换为 截断为零,因此您得到或。doublefloaty .59.5910059int5958

于 2013-02-01T17:44:50.983 回答
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作为整数。

于 2013-02-01T17:56:39.213 回答