C中的浮点舍入

我用浮动遇到了一些奇怪的舍入行为。 下面的代码演示了这个问题。 解决这个问题的最佳方法是什么? 我一直在寻找解决方案,但没有太多运气。

#include int main(void) { float t; t = 5592411; printf("%f\n", 1.5*t); t *= 1.5; printf("%f\n", t); return 0; } 

上面的代码应打印出相同的值,但我使用GCC 4.7.2在我的设置上得到了这个:

8388616.500000

8388616.000000

如果我使用计算器,我得到第一个值,所以我假设第二个值是以某种方式舍入。 我有相同的Fortran代码,它不会对值进行舍入(具有0.5)。

1.5double常数而不是float ,C具有自动升级规则。 所以当你执行1.5*t时会发生什么(i) t被转换为double ; (ii) double乘以double 1.5 ; (iii)打印double精度( %fdouble精度的格式化程序)。

相反, t *= 1.5t提升为double,执行双倍乘法,然后截断结果以将其存储回[单精度] float

有关证据,请尝试:

 float t; t = 5592411; printf("%f\n", 1.5f*t); // multiply a float by a float, for no promotion t *= 1.5; printf("%f\n", t); return 0; 

要么:

 double t; // store our intermediate results in a double t = 5592411; printf("%f\n", 1.5f*t); t *= 1.5; printf("%f\n", t); return 0; 

第一次计算是使用双精度完成的,第二次计算相同,但在赋值为float被截断为单精度。

如果对变量使用double ,则会得到相同的结果。 当精度可能成为问题时,最好在float上使用这种类型。

在第一种情况下,结果是双精度,它可以精确地表示所需的值。

在第二种情况下,结果是一个浮点数,它不能精确地表示所需的值。

尝试使用double,你最终会得到相同的结果。

 #include int main(void) { double t; t = 5592411; printf("%f\n", 1.5*t); t *= 1.5; printf("%f\n", t); return 0; } 

在C代码中编写1.5被解释为double,其精度高于float类型。

第一种情况,

 printf("%f\n", 1.5*t); 

导致t被隐式转换为double(精度更高)然后相乘。 printf函数无论如何都会输出对应于%f的输入,打印结果,这也是一个double

第二种情况是将1.5转换为float类型,其精度较低,无法存储为小细节。

如果要避免此效果,请使用1.5f而不是1.5来使用floats ,或将t的类型更改为double

这是否可行取决于浮动和双打的机器表示。 在典型的32位体系结构上传递浮点数会在参数堆栈上推送4个字节。 传递一个双字符将推送8个字节。 传递一个double但是使用%f要求将它视为一个浮点数,它将查看在我们典型情况下推送的前4个字节。 根据机器表示,这可能接近预期结果,或者可能在左侧字段中显示出来。