我正在使用 GCC 编译一个添加 float 、长整型、整数和字符的程序。当它运行时,结果很糟糕。以下程序意外打印出值 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;
}
最佳答案
你认为“正确的结果”是什么?我猜你认为它是 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 所做的事情?几个原因。首先,它在某些处理器上速度较慢。其次,更重要的是,虽然它可以给出更准确的答案,但程序员不能依赖于此——看似无关的代码更改可能会导致答案在这种行为存在的情况下发生变化。正因为如此,携带额外的精度通常会导致比它解决的问题更多的问题。
关于c - 为什么 GCC 在添加浮点值时会给出意想不到的结果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6794398/