Jav*_*Jav 1 c floating-point optimization casting
我对编译器如何通过如下指令进行float转换感兴趣int:
float x_f = 3.1415
int x = (int)x_f;
Run Code Online (Sandbox Code Playgroud)
特别是谈论速度.它是否像内置处理器指令一样超快?还是需要计算?
如果它float总是包含一个精确的整数(ex :),它也会改变x_f = 3.0000.
编辑:这个问题是针对intel x86处理器使用的gcc编译器.
EDIT2:如果有变化x_f = 3.0吗?
这在很大程度上取决于特定的cpu.由于您对x86感兴趣,原始的387 fpu有一个将float转换为整数的指令,但它不能直接使用,因为它使用默认的舍入模式,而C中的转换需要截断,而不是舍入.因此,以下功能:
int f(float x)
{
return x;
}
Run Code Online (Sandbox Code Playgroud)
编译(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
Run Code Online (Sandbox Code Playgroud)
它正在做什么来保存,更改和恢复fpu控制字以更改舍入模式.
另一方面,如果您正在构建具有可用于浮点的SSE的目标,则可以获得:
.text
.globl f
.type f, @function
f:
cvttss2si 4(%esp), %eax
ret
Run Code Online (Sandbox Code Playgroud)
所以,这真的取决于.
最后,既然你提到你对价值已经是整数的情况特别感兴趣,这没有任何区别.转换的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
Run Code Online (Sandbox Code Playgroud)
请注意,gcc在编译此函数方面做得不好; 它可能产生:
f:
flds 4(%esp)
fistpl 4(%esp)
movl 4(%esp), %eax
ret
Run Code Online (Sandbox Code Playgroud)
这是有效的,因为堆栈上的参数空间属于被调用者,可能会随意破坏.即使它不是,movl (%esp),%eax ; popl %edx当你不在乎什么最终edx是一种愚蠢的写作方式popl %eax......