我正在使用GCC编译一个添加浮点数,长整数,整数和字符的程序。当它运行时,结果很糟糕。以下程序意外打印值34032.101562。
使用Microsoft编译器重新编译会得到正确的结果。
#include <stdio.h>
int main (void) {
const char val_c = 10;
const int val_i = 20;
const long val_l = 34000;
const float val_f = 2.1;
float result;
result = val_c + val_i + val_l + val_f;
printf("%f\n", result);
return 0;
}
答案 0 :(得分:13)
您认为“正确的结果”是什么?我猜你相信它是34032.1。事实并非如此。
2.1无法表示为float
,因此使用最接近的可表示val_f
值初始化float
。在二进制中,2.1是:
10.000110011001100110011001100110011001100110011001...
float
有24位二进制数字,因此二进制中val_f
的值为:
10.0001100110011001100110
表达式resultat = val_c + val_i + val_l + val_f
计算34030 + val_f
,它以单精度计算并导致另一次舍入。
1000010011101110.0
+ 10.0001100110011001100110
-----------------------------------------
1000010011110000.0001100110011001100110
rounds to 24 digits:
-----------------------------------------
1000010011110000.00011010
在十进制中,此结果正好是34032.1015625。因为%f
格式在小数点后打印6位数(除非另有说明),所以再次舍入,printf打印34032.101562
。
现在,为什么在使用MSVC编译时没有得到这个结果?如果编译器选择这样做,C和C ++标准允许以更宽的类型执行浮点计算。 MSVC会对您的计算执行此操作,这意味着34030 + val_f
的结果在传递给printf
之前未进行舍入。在这种情况下,打印的确切浮点值为34032.099999999991268850862979888916015625,由printf舍入为34032.1。
为什么不是所有的编译器都做MSVC的工作?有几个原因。首先,它在某些处理器上速度较慢。其次,更重要的是,虽然它可以提供更准确的答案,但程序员不能依赖于此 - 看似无关的代码更改可能导致答案在出现此行为时发生变化。因此,携带额外的精度通常会导致比解决更多的问题。
答案 1 :(得分:2)
答案 2 :(得分:1)
float 格式只有大约6-7位数的精度。使用%7.1f 或其他合理格式,您会更好地了解结果。
答案 3 :(得分:0)
我在这里看不到任何问题。 2.1在IEEE浮点格式中没有精确的表示,因此,它将整个答案转换为具有大约6-7(正确)sig-figs的浮点数。如果您需要更高的精度,请使用双精度。