2

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

#include<stdio.h>

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)。

4

5 回答 5

8

1.5是一个double常数而不是 afloat并且 C 具有自动提升规则。因此,当您执行1.5*t时,将 (i)t转换为double; (ii)double乘以double 1.5;和 (iii)double被打印(就像%fa 的格式化程序一样double)。

相反,t *= 1.5提升t为双精度,执行双倍乘法,然后截断结果以将其存储回 [单精度] 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;
于 2013-04-03T21:25:16.353 回答
2

第一次计算以双精度完成,第二次计算相同,但在分配给 时截断为单精度float

如果你使用double你的变量,你会得到相同的结果。float每当需要考虑准确性时,最好使用这种类型。

于 2013-04-03T21:24:42.123 回答
1

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

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

尝试使用双精度相同的方法,您最终会得到相同的结果。

#include<stdio.h>

int main(void)
{   
    double t;
    t = 5592411;
    printf("%f\n", 1.5*t);
    t *= 1.5;
    printf("%f\n", t);
    return 0;
}
于 2013-04-03T21:25:22.013 回答
0

用 C 代码编写 1.5 被解释为 double,它比 float 类型具有更高的精度。

第一种情况,

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

导致t被隐式转换为双精度(精度更高),然后相乘。该printf函数将输入对应于%f反正转换,打印结果,这也是一个double.

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

如果您想避免这种影响,请1.5f改用 on 1.5to use floats,或将类型更改为tto double

于 2013-04-03T21:26:09.533 回答
-1

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

于 2013-04-03T21:32:08.863 回答