Хотя другие объяснили, что причиной этой проблемы, я считаю, что «лучше» решение должно быть, чтобы написать условное, если:
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;
}
Да, это несколько строк больше, но это также легче читать и четко понимать, что происходит (и если вам нужно пройти через него в отладчике, вы можете легко увидеть, в каком направлении он идет).
Любой современный компилятор должен иметь возможность конвертировать любой из них в довольно эффективные условные задания, которые делают хорошую работу по предотвращению ветвей (и, следовательно, «плохое предсказание ветвей»).
я подготовил небольшой тест, который я скомпилирован с использованием
g++ -O2 -fno-inline -S -Wall ifs.cpp
Вот источник (я должен был сделать его параметры, чтобы обеспечить компилятор не просто вычислить правильное значение непосредственно и просто сделать mov $12,%rdx
, но на самом деле сделал сравнить и решить, с больше):
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;
}
Сгенерированный код выглядит следующим образом:
_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....
Как вы можете видеть, mine
и original
идентичны, и romano
использует несколько разные регистры и другую форму cmov
, но в остальном они делают то же самое с одинаковым количеством инструкций.
Parenthesizing решает проблему ... –
Еще одна причина «не пытаться быть умной» с условными выражениями и использовать «if» вместо этого. Компилятор будет делать то же самое в любом случае [при условии, что вы добавите соответствующие скобки, чтобы он делал то, что вы действительно хотели). Иногда термины могут быть полезны, но это хороший пример того, что НЕ делать с ними. –
(И вообще, почему бы и нет: 'maxx = x1> x2? X1: x2'? –