我对以下C程序的输出有疑问。我尝试使用VisualWeb6.0和C++ MinGW32编译它(gcc 3.4.2)。
#include <stdio.h>
int main() {
int x = 2147483647;
printf("%f\n", (float)2147483647);
printf("%f\n", (float)x);
return 0;
}产出如下:
2147483648.000000
2147483647.000000我的问题是:为什么两条线是不同的?当您将整数值2147483647转换为IEEE 754浮点格式时,它将被近似为2147483648.0。所以,我预计这两行都等于2147483648.000000。
编辑:值"2147483647.000000“不能是一个单精度浮点值,因为数字2147483647不能准确地表示为IEEE 754单精度浮点格式而不丢失精度。
发布于 2014-11-24 22:16:56
在这两种情况下,代码都试图从某种整数类型转换为float,然后转换为double。double转换的发生是因为它是传递给变量函数的float值。
检查FLT_EVAL_METHOD的设置,怀疑它的值为1或2 (OP用至少一个编译器报告2 )。这允许编译器计算float“.操作和常数的范围和精度”大于float。
您的编译器优化了(float)x,直接将int转换为double算法。这是运行时的性能改进。
(float)2147483647是一种编译时强制转换,并为int到float到double的准确性进行了优化,因为这里的性能不是问题。
Edit2有趣的是,C11规范比C99规范更具体,添加了“除了赋值和强制转换.”。这意味着C99编译器有时允许int到double直接转换,而无需先通过float,并且C11被修改为显然不允许跳过强制转换。
由于C11正式排除了这种行为,现代的编译器不应该这样做,但是旧的编译器应该这样做,比如OP的可能--因此,按照C11标准,这是一个bug。除非发现了其他一些C99或C89规范,否则这似乎是允许的编译器行为。
编辑由@Keith,@tmyklebu,@Matt McNabb,编译器,即使是非零FLT_EVAL_METHOD,一起编辑,应该会产生2147483648.0...。因此,要么编译器优化标志显式凌驾于正确的行为之上,要么编译器有一个角错误。
C99dr§5.2.4.2.2 8具有浮动操作数的操作值和受通常算术转换限制的值以及浮动常数的值,其计算格式的范围和精度可能大于该类型所需的范围和精度。评估格式的使用以FLT_EVAL_METHOD:的实现定义值为特征。
-1不确定;
根据类型的范围和精度评估所有操作和常数;
1根据float型和double型的范围和精度评价long double运算和常数,根据long double类型的范围和精度评价long double运算和常数;
2根据long double类型的范围和精度评估所有操作和常数。
C11dr§5.2.4.2.2 9除了赋值和转换(这消除了所有额外的范围和精度)外,带有浮动操作数的运算符产生的值以及受通常算术转换的值和浮动常数的值将被计算成一种格式,其范围和精度可能大于该类型所要求的范围和精度。评估格式的使用以FLT_EVAL_METHOD的实现定义值为特征。
-1 (与C99相同)
0(与C99相同)
1(与C99相同)
2(与C99相同)
发布于 2014-11-24 20:27:40
在第一个printf上,从整数到浮点数的转换由编译器完成。在第二个方面,它是由C运行时库完成的。没有什么特别的理由让他们在精确的范围内提供相同的答案。
发布于 2014-11-24 22:24:50
Visual C++ 6.0是上世纪发布的,我相信它早于标准C++。毫不奇怪的是,VC++ 6.0显示出坏的行为。
你也会注意到gcc-3.4.2是从2004年开始的.实际上,您使用的是32位编译器。gcc在x86 在浮点数学上玩得很快而且很松散。上报道。如果gcc将FLT_EVAL_METHOD设置为非零,这在技术上可能是符合C标准的。
https://stackoverflow.com/questions/27113114
复制相似问题