Tandis que d'autres ont expliqué qu'en soit la cause du problème est, je pense que la "meilleure" solution devrait être d'écrire le conditionnel avec si:
int x1 = 10, x2=20, y1=132, y2=12, minx, miny, maxx, maxy;
if (x1<=x2)
{
minx=x1;
maxx=x2;
}
else
{
minx=x2;
maxx=x1;
}
if (y1<=y2)
{
miny=y1;
maxy=y2;
}
else
{
miny=y2;
maxy=y1;
}
Oui, il est plusieurs lignes en plus, mais c'est aussi plus facile à lire et clair exactement ce qui se passe (et si vous avez besoin à l'étape à travers elle dans le débogueur, vous pouvez facilement voir de quel côté il va).
Moderne compilateur doit être en mesure de convertir l'une de ces vers assez efficace conditionnelle affectations qui fait un bon travail en évitant les branches (et donc la "mauvaise direction de la prévision").
J'ai préparé un petit test, j'ai compilé à l'aide de
g++ -O2 -fno-inline -S -Wall ifs.cpp
Voici le code source (j'ai dû le faire paramètres pour s'assurer que le compilateur n'a pas simplement calculer la valeur correcte directement et simplement n' mov $12,%rdx
, mais le fait de les comparer et de décider avec qui est plus grand):
void mine(int x1, int x2, int y1, int y2)
{
int minx, miny, maxx, maxy;
if (x1<=x2)
{
minx=x1;
maxx=x2;
}
else
{
minx=x2;
maxx=x1;
}
if (y1<=y2)
{
miny=y1;
maxy=y2;
}
else
{
miny=y2;
maxy=y1;
}
cout<<"minx="<<minx<<"\n";
cout<<"maxx="<<maxx<<"\n";
cout<<"miny="<<miny<<"\n";
cout<<"maxy="<<maxy<<"\n";
}
void original(int x1, int x2, int y1, int y2)
{
int minx, miny, maxx, maxy;
x1<=x2 ? (minx=x1,maxx=x2) : (minx=x2,maxx=x1);
y1<=y2 ? (miny=y1,maxy=y2) : (miny=y2,maxy=y1);
cout<<"minx="<<minx<<"\n";
cout<<"maxx="<<maxx<<"\n";
cout<<"miny="<<miny<<"\n";
cout<<"maxy="<<maxy<<"\n";
}
void romano(int x1, int x2, int y1, int y2)
{
int minx, miny, maxx, maxy;
minx = ((x1 <= x2) ? x1 : x2);
maxx = ((x1 <= x2) ? x2 : x1);
miny = ((y1 <= y2) ? y1 : y2);
maxy = ((y1 <= y2) ? y2 : y1);
cout<<"minx="<<minx<<"\n";
cout<<"maxx="<<maxx<<"\n";
cout<<"miny="<<miny<<"\n";
cout<<"maxy="<<maxy<<"\n";
}
int main()
{
int x1=10, x2=20, y1=132, y2=12;
mine(x1, x2, y1, y2);
original(x1, x2, y1, y2);
romano(x1, x2, y1, y2);
return 0;
}
Le code généré ressemble à ceci:
_Z4mineiiii:
.LFB966:
.cfi_startproc
movq %rbx, -32(%rsp)
movq %rbp, -24(%rsp)
movl %ecx, %ebx
movq %r12, -16(%rsp)
movq %r13, -8(%rsp)
movl %esi, %r12d
subq $40, %rsp
movl %edi, %r13d
cmpl %esi, %edi
movl %edx, %ebp
cmovg %edi, %r12d
cmovg %esi, %r13d
movl $_ZSt4cout, %edi
cmpl %ecx, %edx
movl $.LC0, %esi
cmovg %edx, %ebx
cmovg %ecx, %ebp
.... removed actual printout code that is quite long and unwieldy...
_Z8originaliiii:
movq %rbx, -32(%rsp)
movq %rbp, -24(%rsp)
movl %ecx, %ebx
movq %r12, -16(%rsp)
movq %r13, -8(%rsp)
movl %esi, %r12d
subq $40, %rsp
movl %edi, %r13d
cmpl %esi, %edi
movl %edx, %ebp
cmovg %edi, %r12d
cmovg %esi, %r13d
movl $_ZSt4cout, %edi
cmpl %ecx, %edx
movl $.LC0, %esi
cmovg %edx, %ebx
cmovg %ecx, %ebp
... print code goes here ...
_Z6romanoiiii:
movq %rbx, -32(%rsp)
movq %rbp, -24(%rsp)
movl %edx, %ebx
movq %r12, -16(%rsp)
movq %r13, -8(%rsp)
movl %edi, %r12d
subq $40, %rsp
movl %esi, %r13d
cmpl %esi, %edi
movl %ecx, %ebp
cmovle %edi, %r13d
cmovle %esi, %r12d
movl $_ZSt4cout, %edi
cmpl %ecx, %edx
movl $.LC0, %esi
cmovle %edx, %ebp
cmovle %ecx, %ebx
... printout code here....
Comme vous pouvez le voir, mine
et original
est identique, et romano
utilise légèrement différents registres et une forme différente de l' cmov
, mais sinon, ils font la même chose dans le même nombre d'instructions.