在c ++中奇怪的双重转换行为

时间:2009-12-07 15:41:55

标签: c++ type-conversion

以下程序显示了我在c ++中看到的奇怪的双向转换行为:

#include <stdlib.h>
#include <stdio.h>

int main() {
  double d = 33222.221;
  printf("d = %9.9g\n",d);

  d *= 1000;
  int i = (int)d;

  printf("d = %9.9g | i = %d\n",d,i);

  return 0;
}

当我编译并运行程序时,我看到:

g++ test.cpp
./a.out
d = 33222.221
d =  33222221 | i = 33222220

为什么我不等于33222221? 编译器版本是GCC 4.3.0

5 个答案:

答案 0 :(得分:10)

浮点表示几乎从不精确(仅在特殊情况下)。每个程序员都应该阅读:What Every Computer Scientist Should Know About Floating-Point Arithmetic

简而言之 - 您的号码可能是33222220.9999999999999999999999999999999999999999999999999999999999999999998(或类似名称),截断后变为33222220。

答案 1 :(得分:1)

当您附加调试器并检查值时,您会看到d的值实际为33222220.999999996,在转换为整数时会被正确截断为33222220。

可以存储在双变量中的数量有限,而33222221不是其中之一。

答案 2 :(得分:0)

由于浮点近似,33222.221实际上可能是33222.220999999999999。乘以1000得出33222220.999999999999。转换为整数会忽略所有小数(向下舍入),最终结果为33222220。

答案 3 :(得分:0)

如果将printf()调用中的“9.9g”更改为17.17以使用64位IEEE 754 FP编号恢复所有可能的精度数字,则可获得33222220.999999996作为double值。然后int转换是有道理的。

答案 4 :(得分:0)

我不想重复其他评论的解释。

所以,这里只是一个避免问题的建议:

  1. 尽可能避免使用浮点算术(特别是涉及计算时)。

  2. 如果真的需要浮点算术,你一定不能用算子==来比较数字!使用你自己的比较函数(或使用一些库提供的函数),使用某种epsilon比较(绝对或相对于数字的分数)做类似“几乎相等”的比较。

  3. 例如,参见优秀的文章

    http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
    
    而是由布鲁斯道森代替!

    的Stefan