1

我对编译器如何将 afloat转换为intby 指令感兴趣,例如:

    float x_f = 3.1415
    int x = (int)x_f;

特别是谈到速度。它是否像内置处理器指令一样超快?还是需要计算?

如果它float总是包含一个精确的整数(例如:),我也会徘徊x_f = 3.0000

编辑:这个问题适用于 intel x86 处理器上使用的 gcc 编译器。

EDIT2:它会改变什么x_f = 3.0吗?

4

2 回答 2

9

这在很大程度上取决于特定的 cpu。由于你对x86感兴趣,原来的387 fpu有一个指令可以将float转换为integer,但不能直接使用,因为它使用默认的舍入模式,而C中的转换需要截断,而不是舍入。因此,以下功能:

int f(float x)
{
    return x;
}

编译为(使用gcc -O3 -fno-asynchronous-unwind-tables, 以避免 asm 中的杂物):

        .text
        .p2align 4,,15
        .globl  f
        .type   f, @function
f:
        subl    $8, %esp
        fnstcw  6(%esp)
        movw    6(%esp), %ax
        movb    $12, %ah
        movw    %ax, 4(%esp)
        flds    12(%esp)
        fldcw   4(%esp)
        fistpl  (%esp)
        fldcw   6(%esp)
        movl    (%esp), %eax
        addl    $8, %esp
        ret

它在做什么它保存、更改和恢复 fpu 控制字以更改舍入模式。

另一方面,如果您正在为具有可用于浮点的 SSE 的目标构建,您将获得:

        .text
        .globl  f
        .type   f, @function
f:
        cvttss2si       4(%esp), %eax
        ret

所以,这真的取决于。

最后,由于您提到您对值已经是整数的情况特别感兴趣,因此这没有任何区别。几乎可以肯定要转换的 cpu 操作不在乎。但是,在这种情况下,您可以作弊:由于您知道输入是整数,因此舍入和截断会产生相同的结果,并且您可以使用lrintf而不是强制转换或隐式转换为浮点数。这应该是对不使用 sse 进行数学运算的 x86 目标的重大改进,尤其是在编译器识别lrintf并内联它的情况下。这是相同的函数,使用lrintf(x)而不是x,添加了-fno-math-errno选项(否则 gcc 假定 libm 可能想要设置errno,因此不会替换调用):

f:
        pushl   %eax
        flds    8(%esp)
        fistpl  (%esp)
        movl    (%esp), %eax
        popl    %edx
        ret

注意 gcc 在编译这个函数方面做得很糟糕;它可能会产生:

f:
        flds    4(%esp)
        fistpl  4(%esp)
        movl    4(%esp), %eax
        ret

这是有效的,因为堆栈上的参数空间属于被调用者,并且可以随意破坏。即使不是,movl (%esp),%eax ; popl %edx当你不在乎结果是什么时,这edx是一种愚蠢的写作方式popl %eax......

于 2013-05-07T14:46:13.213 回答
2

当然,如果您要构建的处理器具有超快的处理方式,它可能会超快。C 不要求处理器具有此类指令,因此它将取决于您正在构建的编译器和处理器。

换句话说,“这取决于”。

于 2013-05-07T14:35:56.910 回答