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

时间:2013-08-24 10:54:59

标签: c casting floating-point pow tcc

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

#include <stdio.h>
#include <math.h>

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

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

3 个答案:

答案 0 :(得分:6)

汇编代码中的一些调查。 (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。 Read more...

enter image description here


解决方案:

使用(int)float强制转换为int后,您应该会遇到此数字错误,因为此转换会将[0,1]之间的值截断为零。

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

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

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

答案 1 :(得分:2)

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

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

答案 2 :(得分:0)

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

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

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