有人可以解释这种行为吗?
test.c的:
#include <stdio.h>
int main(void)
{
printf("%d, %d\n", (int) (300.6000/0.05000), (int) (300.65000/0.05000));
printf("%f, %f\n", (300.6000/0.05000), (300.65000/0.05000));
return 0;
}
$ gcc test.c
$ ./a.out
6012, 6012
6012.000000, 6013.000000
我检查了汇编代码,它将第一个printf的参数都设置为6012,所以它似乎是一个编译时错误。
答案 0 :(得分:9)
运行
#include <stdio.h>
int main(void)
{
printf("%d, %d\n", (int) (300.6000/0.05000), (int) (300.65000/0.05000));
printf("%.20f %.20f\n", (300.6000/0.05000), (300.65000/0.05000));
return 0;
}
它应该更清楚。第二个的值(在浮点除法之后,这不是精确的)是~6012.9999999999991,所以当你用(int)截断它时,gcc足够聪明,可以在编译时输入6012。
当您打印浮动时,printf默认将它们格式化为仅显示6位精度,这意味着第二个打印为6013.000000。
答案 1 :(得分:7)
printf()
会对浮点数进行舍入。如果你添加更多精度,你可以看到发生了什么:
$ cat gccfloat.c
#include <stdio.h>
int main(void)
{
printf("%d, %d\n", (int) (300.6000/0.05000), (int) (300.65000/0.05000));
printf("%.15f, %.15f\n", (300.6000/0.05000), (300.65000/0.05000));
return 0;
}
$ ./gccfloat
6012, 6012
6012.000000000000000, 6012.999999999999091
答案 2 :(得分:1)
听起来像是一个舍入错误。正在计算300.65000/0.05000
(浮点数),如6012.99999999
。当作为int进行转换时,它会被截断为6012
。当然这在编译器优化中都是预先计算的,所以最终的二进制文件只包含值6012
,这就是你所看到的。
您在第二个陈述中看不到相同的原因是因为它是舍入以供printf
显示,而不是截断,因为当你转向int
时会发生什么。 (参见@John Kugelman的回答。)
答案 3 :(得分:0)
很明显,但没有人告诉过:两个师的结果都是自然数。 那么编译器在哪里出错了?也许。 而且我在MS VS 2015中也重现了同样的问题,所以看起来错误的编译器是2.而且我打赌一分钱,LLVM也做同样的事情。 也许编译器是对的? 回答这个问题不适合我,我只是注意到以下几点:看起来这是一个“带小数的文字除法”的隐式演员问题加倍。
下面的小测试表明,一个double的内容,从编译时分配的2个文字的除法结果,没有强制转换,是错误的。 如果先前将结果转换为浮点数,则结果将变为正确。
Action<int>
此输出跟随MS-VS.2015:
#include <stdio.h>
int main(void)
{
float fb = (300.65000 / 0.05000);
float fa = (300.6000 / 0.05000);
float fb1 = 6013.0;
float fa1 = 6012.0;
char bufffa[sizeof(float) * 2 +1] = { 0 };
char bufffb[sizeof(float) * 2 +1] = { 0 };
double db = (300.65000 / 0.05000);
double da = (300.6000 / 0.05000);
double db1 = 6013.0;
double da1 = 6012.0;
char buffda[sizeof(double) * 2 + 1] = { 0 };
char buffdb[sizeof(double) * 2 + 1] = { 0 };
int i;
printf("sizeof(float)=%d, sizeof(double)=%d\n", sizeof(float), sizeof(double));
for (i = 0; i < sizeof(fa); i++)
{
sprintf(bufffa + (i * 2), "%02X", ((unsigned char*)(&fa))[i]);
sprintf(bufffb + (i * 2), "%02X", ((unsigned char*)(&fb))[i]);
}
printf("OK: float binary form (compile time division): fa=%s, fb=%s\n", bufffa, bufffb);
for (i = 0; i < sizeof(fa1); i++)
{
sprintf(bufffa + (i * 2), "%02X", ((unsigned char*)(&fa1))[i]);
sprintf(bufffb + (i * 2), "%02X", ((unsigned char*)(&fb1))[i]);
}
printf("OK: float binary form (NOT compile time division): fa1=%s, fb1=%s\n", bufffa, bufffb);
for (i = 0; i < sizeof(da); i++)
{
sprintf(buffda + (i * 2), "%02X", ((unsigned char*)(&da))[i]);
sprintf(buffdb + (i * 2), "%02X", ((unsigned char*)(&db))[i]);
}
printf("NOT OK: double binary form (compile time division): da=%s, db=%s\n", buffda, buffdb);
for (i = 0; i < sizeof(da1); i++)
{
sprintf(buffda + (i * 2), "%02X", ((unsigned char*)(&da1))[i]);
sprintf(buffdb + (i * 2), "%02X", ((unsigned char*)(&db1))[i]);
}
printf("OK: double binary form (NOT compile time division):da1=%s, db1=%s\n", buffda, buffdb);
printf("incorrect values:\n");
printf("printf(int) compile time division, literal: a=%d, b=%d\n", (int)(300.6000 / 0.05000), (int)(300.65000 / 0.05000));
printf("printf(float) compile time division, literal: a=%.15f, b=%.15f\n", (300.6000 / 0.05000), (300.65000 / 0.05000));
printf("printf(double) compile time division: da=%.15f, db=%.15f\n", da, db);
printf("correct values:\n");
printf("printf(int) compile time division, literal with cast: a=%d, b=%d\n", (int)(300.6000 / 0.05000), (int)(float)(300.65000 / 0.05000));
printf("printf(float) compile time division, literal with cast: a=%.15f, b=%.15f\n", (float)(300.6000 / 0.05000), (float)(300.65000 / 0.05000));
printf("printf(float) compile time division: fa=%.15f, fb=%.15f\n", fa, fb);
printf("printf(float) NOT compile time division: fa1=%.15f, fb1=%.15f\n", fa1, fb1);
printf("printf(double) NOT compile time division: da1=%.15f, db1=%.15f\n", da1, db1);
return 0;
}