错误的Visual C浮动/双重转换?

时间:2010-04-07 08:53:24

标签: c floating-point visual-studio-2005 double floating-accuracy

在Visual C ++中,我在C ++程序中编写了以下示例:

float f1 = 42.48f;
double d1 = 42.48;
double d2 = f1;

我用Visual Studio 2005编译了程序。  在调试器中,我看到以下值:

f1  42.480000   float
d1  42.479999999999997  double
d2  42.479999542236328  double

我知道的d1是好的,但是d2错了。

问题也发生在/ fp =精确,与/ fp = strict一样,/ fp = fast。

问题出在这里?任何提示如何避免这个问题?这导致严重的数字问题。

3 个答案:

答案 0 :(得分:4)

这不是VC ++或类似的问题 - 这是浮点数如何存储在计算机上的基本问题。有关详细信息,请参阅IEEE-754

问题是从float转换为double,以便从double转换回float会导致与您开始时完全相同的浮点值。除了在需要更长的精度时仅使用双精度,我不知道有任何方法可以减少精度。尝试将round转换后的浮点数设置为两位小数可能会将其设置为正确的值,但我不确定。

答案 1 :(得分:3)

f1中的值和d2中的值都代表完全相同的数字。这个数字不完全是42.480000,也不是42.479999542236328,尽管它确实有一个终止的十进制表示。当显示浮动时,调试视图在浮点数的精度上合理地舍入,并且当显示双精度时,它以双精度的精度舍入。因此,当您转换并显示为双倍时,您会看到神秘值的两倍。

d1包含比神秘值更好的近似值4.48,因为d1包含最接近4.48的双倍,而f1d2仅包含最接近的浮点值到4.48。你期望d2包含什么? f1不能“记住”它“真的应该是”4.48,所以当它转换为double时,它会变得“更准确”。

避免它的方法取决于你指的是哪个严重的数字问题。如果问题是d1和d2不相等,并且您认为它们应该相等,那么答案是在比较中包含一个小容差,例如,将d1 == d2替换为:

fabs(d1 - d2) <= (d2 * FLT_EPSILON)

这只是一个例子,但我没有检查它是否涉及这种情况。您必须选择适合您的容差,并且您可能还需要担心许多边缘情况 - d2可能为零,值可能是无穷大或NaN,可能是其他值。

如果问题是d2不是足够准确的算法值来产生准确的结果,那么你必须避免使用float值,和/或使用更加数字稳定的算法。

答案 2 :(得分:2)

这里发生的事情没有错。

由于浮点数在内存中的表示方式,42.479999999999997是双精度数最接近的42.48。

阅读本文: http://docs.sun.com/source/806-3568/ncg_goldberg.html

它解释了那里发生的事情。遗憾的是,你无法对其进行存储。