编译器很可能在底层对两者都做同样的事情-至少是现代的胜任的编译器。
但是,至少对于浮点数,如果要处理无穷大,非数字(NaN),负零等所有特殊情况,最终会写几十行。
读取a = (a < 0)?-a:a正在获取绝对值比读取小于零的绝对值要容易。
如果编译器“愚蠢”,则可能会为a = (a < 0)?-a:a编写更糟糕的代码,因为它会强制if(即使它是隐藏的),并且可能比该处理器上的内置浮点abs指令还要糟糕( 除了特殊价值的复杂性之外)
香港vps
Clang(6.0-pre-release)和gcc(4.9.2)都会为第二种情况生成WORSE代码。
我写了这个小样本:
#include
#include
extern int intval;
extern float floatval;
void func1()
{
int a = std::abs(intval);
float f = std::abs(floatval);
intval = a;
floatval = f;
}
void func2()
{
int a = intval < 0?-intval:intval;
float f = floatval < 0?-floatval:floatval;
intval = a;
floatval = f;
}
clang为func1编写以下代码:
_Z5func1v: # @_Z5func1v
movl intval(%rip), %eax
movl %eax, %ecx
negl %ecx
cmovll %eax, %ecx
movss floatval(%rip), %xmm0 # xmm0 = mem[0],zero,zero,zero
andps .LCPI0_0(%rip), %xmm0
movl %ecx, intval(%rip)
movss %xmm0, floatval(%rip)
retq
_Z5func2v: # @_Z5func2v
movl intval(%rip), %eax
movl %eax, %ecx
negl %ecx
cmovll %eax, %ecx
movss floatval(%rip), %xmm0
movaps .LCPI1_0(%rip), %xmm1
xorps %xmm0, %xmm1
xorps %xmm2, %xmm2
movaps %xmm0, %xmm3
cmpltss %xmm2, %xmm3
movaps %xmm3, %xmm2
andnps %xmm0, %xmm2
andps %xmm1, %xmm3
orps %xmm2, %xmm3
movl %ecx, intval(%rip)
movss %xmm3, floatval(%rip)
retq
g ++ func1:
_Z5func1v:
movss .LC0(%rip), %xmm1
movl intval(%rip), %eax
movss floatval(%rip), %xmm0
andps %xmm1, %xmm0
sarl $31, %eax
xorl %eax, intval(%rip)
subl %eax, intval(%rip)
movss %xmm0, floatval(%rip)
ret
g ++ func2:
_Z5func2v:
movl intval(%rip), %eax
movl intval(%rip), %edx
pxor %xmm1, %xmm1
movss floatval(%rip), %xmm0
sarl $31, %eax
xorl %eax, %edx
subl %eax, %edx
ucomiss %xmm0, %xmm1
jbe .L3
movss .LC3(%rip), %xmm1
xorps %xmm1, %xmm0
.L3:
movl %edx, intval(%rip)
movss %xmm0, floatval(%rip)
ret
请注意,两种情况在第二种形式中都特别复杂,在gcc情况下,它使用分支。 Clang使用更多指令,但没有分支。 我不确定哪种处理器型号上速度更快,但是显然更多的指令很少更好。
46199918