我对编译器如何将 afloat
转换为int
by 指令感兴趣,例如:
float x_f = 3.1415
int x = (int)x_f;
特别是谈到速度。它是否像内置处理器指令一样超快?还是需要计算?
如果它float
总是包含一个精确的整数(例如:),我也会徘徊x_f = 3.0000
。
编辑:这个问题适用于 intel x86 处理器上使用的 gcc 编译器。
EDIT2:它会改变什么x_f = 3.0
吗?
我对编译器如何将 afloat
转换为int
by 指令感兴趣,例如:
float x_f = 3.1415
int x = (int)x_f;
特别是谈到速度。它是否像内置处理器指令一样超快?还是需要计算?
如果它float
总是包含一个精确的整数(例如:),我也会徘徊x_f = 3.0000
。
编辑:这个问题适用于 intel x86 处理器上使用的 gcc 编译器。
EDIT2:它会改变什么x_f = 3.0
吗?
这在很大程度上取决于特定的 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
......
当然,如果您要构建的处理器具有超快的处理方式,它可能会超快。C 不要求处理器具有此类指令,因此它将取决于您正在构建的编译器和处理器。
换句话说,“这取决于”。