<分区>
我对编译器如何通过如下指令将 float
转换为 int
很感兴趣:
float x_f = 3.1415
int x = (int)x_f;
尤其是速度。它像内置处理器指令一样超快吗?还是需要计算?
如果 float
总是包含一个精确的整数(例如:x_f = 3.0000
),我也会想知道它是否改变了什么。
编辑:这个问题是针对在英特尔 x86 处理器上使用的 gcc 编译器的。
EDIT2:如果 x_f = 3.0
它会改变什么吗?
<分区>
我对编译器如何通过如下指令将 float
转换为 int
很感兴趣:
float x_f = 3.1415
int x = (int)x_f;
尤其是速度。它像内置处理器指令一样超快吗?还是需要计算?
如果 float
总是包含一个精确的整数(例如:x_f = 3.0000
),我也会想知道它是否改变了什么。
编辑:这个问题是针对在英特尔 x86 处理器上使用的 gcc 编译器的。
EDIT2:如果 x_f = 3.0
它会改变什么吗?
最佳答案
这在很大程度上取决于特定的 cpu。由于你对x86感兴趣,原来的387 fpu有一个将float转换为整数的指令,但是不能直接使用,因为它使用默认的舍入模式,而C中的转换需要截断,而不是舍入。因此,以下函数:
int f(float x)
{
return x;
}
编译为(使用 gcc -O3 -fno-asynchronous-unwind-tables
,以避免 asm 中的 crud):
.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
而不是强制转换或隐式转换为 float 。这应该是对不使用 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 - 在 C 中将 float 转换为处理器内部的 int,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16421734/