以下程序显示了我在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
答案 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)
我不想重复其他评论的解释。
所以,这里只是一个避免问题的建议:
尽可能避免使用浮点算术(特别是涉及计算时)。
如果真的需要浮点算术,你一定不能用算子==来比较数字!使用你自己的比较函数(或使用一些库提供的函数),使用某种epsilon比较(绝对或相对于数字的分数)做类似“几乎相等”的比较。
例如,参见优秀的文章
http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
而是由布鲁斯道森代替!
的Stefan