Le compilateur va probablement faire la même chose pour les deux au fond de la couche d'au moins un moderne compétente compilateur.
Cependant, au moins pour la virgule flottante, vous finirez par l'écriture de quelques dizaines de lignes, si vous le souhaitez traiter tous les cas particuliers de l'infini, et non pas un nombre (NaN), négatif zéro et ainsi de suite.
Ainsi que c'est plus facile à lire qu' abs
est de prendre la valeur absolue de la lecture que s'il fait moins de zéro, plus le nier.
Si le compilateur est "stupide", il peut bien faire de pire code pour a = (a < 0)?-a:a
,, parce qu'il impose une if
(même si elle est cachée), et qui pourrait bien être pire que dans le haut-virgule flottante abs instruction sur ce processeur (en dehors de la complexité de valeurs spéciales)
Les deux Clang (6.0-pre-release) et gcc (4.9.2) génère PIRE code pour le deuxième cas.
J'ai écrit ce petit échantillon:
#include <cmath>
#include <cstdlib>
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 fait ce code pour 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
Notez que les deux cas sont nettement plus complexe dans la deuxième forme, et dans le ccag cas, il utilise une branche. Clang utilise plus d'instructions, mais aucune branche. Je ne suis pas sûr de ce qui est plus rapide sur le processeur modèles, mais de toute évidence plus d'instructions est rarement mieux.