pow()转换为整数,意外结果

我在C编程语言中使用整数强制转换为pow()函数时遇到了一些问题。 我正在使用的编译器是Windows平台的Tiny C编译器 (tcc版本0.9.24)。 执行以下代码时,它输出意外结果100, 99

 #include  #include  int main(void) { printf("%d, ", (int) pow(10, 2)); printf("%d", (int) pow(10, 2)); return 0; } 

但是,在此在线编译器中,输出符合预期: 100, 100 。 我不知道是什么导致了这种行为。 有什么想法吗? 我编程错误,编译错误?

您在tcc中发现了一个错误。 感谢那。 该补丁刚刚被提交到存储库。 它将包含在下一个版本中,但这可能需要一段时间。 你当然可以拉动源并自己构建它。 补丁就在这里

http://repo.or.cz/w/tinycc.git/commitdiff/73faaea227a53e365dd75f1dba7a5071c7b5e541

汇编代码中的一些调查。 (OllyDbg的)

 #include  #include  int main(void) { int x1 = (int) pow(10, 2); int x2 = (int) pow(10, 2); printf("%d %d", x1, x2); return 0; } 

相关的assembly部分:

 FLD QWORD PTR DS:[402000] // Loads 2.0 onto stack SUB ESP,8 FSTP QWORD PTR SS:[ESP] FLD QWORD PTR DS:[402008] // Loads 10.0 onto stack SUB ESP,8 FSTP QWORD PTR SS:[ESP] CALL  // Calls pow API // Returned value 100.00000000000000000 ... FLDCW WORD PTR DS:[402042] // OH! LOOK AT HERE ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... FLD QWORD PTR DS:[402010] // Loads 2.0 onto stack SUB ESP,8 FSTP QWORD PTR SS:[ESP] FLD QWORD PTR DS:[402018] // Loads 10.0 onto stack SUB ESP,8 FSTP QWORD PTR SS:[ESP] CALL  // Calls pow API again // Returned value 99.999999999999999990 

两次调用生成的代码相同,但输出不同。 我不知道为什么tcc把FLDCW放在那里。 但是两个不同值的主要原因是那条线。

在该行之前,圆形尾数精度控制位是53 (10),但在执行该行(它加载FPU寄存器控制)后,它将设置为64位(11)。 另一方面, 舍入控制 最接近,因此结果为99.999999999999999990。 阅读更多…

在此处输入图像描述


解:

在使用(int)float转换为int ,您应该期望这个数字错误,因为此转换会将[0,1之间的值]截断为零。

假设10 2是99.9999999999。 在演员之后,结果是99。

尝试在将结果转换为整数之前对结果进行舍入,例如:

 printf("%d", (int) (floor(pow(10, 2) + 0.5)) ); 

看起来舍入方法可能会改变,因此需要ASM指令才能重置FPU。 在Windows上的FreeBASIC中,即使在第一次尝试中我也得到99.9999 ,因此我认为在第一次尝试之后它将是一致的99.9999 。 (但我确实称这种未定义的行为,不仅仅是C运行时的pow()中的一个错误。)

所以我的建议是不要进行圆形转换。 要避免此类问题,请使用,例如:

int x1 = (int)(pow(10, 2)+.5);