对汇编代码的一些调查。(OllyDbg)
#include <stdio.h>
#include <math.h>
int main(void)
{
int x1 = (int) pow(10, 2);
int x2 = (int) pow(10, 2);
printf("%d %d", x1, x2);
return 0;
}
相关的组装部分:
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 <JMP.&msvcrt.pow> // 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 <JMP.&msvcrt.pow> // Calls pow API again
// Returned value 99.999999999999999990
两次调用生成的代码相同,但输出不同。我不知道为什么 tcc 放在FLDCW
那里。但是两个不同值的主要原因是那条线。
在该行之前,圆形尾数精度控制位为 53 位(10),但在执行该行后(它加载 FPU 寄存器控制),它将设置为 64 位(11)。另一方面,舍入控制是最接近的,因此结果为 99.999999999999999990。阅读更多...
解决方案:
使用(int)
to 将 a强制转换float
为 anint
后,您应该预料到这个数字错误,因为这种强制转换会将 [0, 1) 之间的值截断为零。
假设 10 2是 99.9999999999。在那次演员之后,结果是99。
尝试在将结果转换为整数之前对其进行四舍五入,例如:
printf("%d", (int) (floor(pow(10, 2) + 0.5)) );