В С++ лучше ли ограничить значение с помощью std:: min или ветки if?
Очень распространенный шаблон в программировании - это ограничение максимального значения после некоторого обновления. Я хотел бы знать, есть ли разница между двумя этими двумя частями кода, и если вам нужно быть предпочтительным:
value += increment;
value = std::min(value, valueMax);
против
value += increment;
if (value > valueMax)
value = valueMax;
Мое мышление заключается в том, что это сводится к тому, что у процессоров есть инструкции для принятия двух значений и получения минимальной суммы. Если это так, вызов std:: min должен привести к этой инструкции и избежать ненужной ветки. Если нет, вторая версия избегает ненужного присваивания, когда значение <= значениеMax.
Я не очень хорошо разбираюсь в подобных вещах, но я уверен, что там есть хакеры из старой школы, которые это узнают. Им я спрашиваю: что лучше?
Ответы
Ответ 1
Современные компиляторы достаточно умны, чтобы генерировать один и тот же код в обоих случаях. Например, 32-разрядный GCC генерирует:
addl %esi, %edi
cmpl %edx, %edi
movl %edi, %eax
cmovgl %edx, %eax
64-бит Clang:
%1 = add nsw i32 %increment, %value
%2 = icmp sgt i32 %1, %valueMax
%value = select i1 %2, i32 %valueMax, i32 %1
Ответ 2
В VC10 on Release для следующего кода мы имеем следующую сборку:
int main(int argc, char *argv[])
{
int dummyValue = 0, valueMax = 3000, value = valueMax + 1;
cin >> valueMax;
cin >> value;
dummyValue = std::min(value, valueMax);
cout << dummyValue;
cin >> valueMax;
cin >> value;
if (value > valueMax)
dummyValue = valueMax;
cout << dummyValue;
return 0;
}
Сформирован:
24: dummyValue = std::min(value, valueMax);
00E112AF mov eax,dword ptr [valueMax]
00E112B2 cmp eax,dword ptr [value]
00E112B5 lea edx,[value]
00E112B8 lea ecx,[valueMax]
00E112BB cmovge ecx,edx // <-- this is our conditional assignment
00E112BE mov esi,dword ptr [ecx]
и
if (value > valueMax)
dummyValue = valueMax
00E112ED mov eax,dword ptr [valueMax]
00E112F0 cmp dword ptr [value],eax
00E112F3 mov ecx,dword ptr ds:[0E13038h]
00E112F9 cmovg esi,eax
Таким образом, оба случая оптимизированы для cmovge
или cmovg
.
Я все равно поеду с std::min
, потому что он показывает намерение лучше, чем оператор if
. Он оптимизировался и стал более читаемым.
Ответ 3
Ответ зависит от типа значения. Код может быть эффективно оптимизирован, если все операции полностью прозрачны для оптимизатора кода, что будет иметь место, если значение является простым целым числом. Но ваш код также будет компилироваться, если значение равно std::string, а затем вторая версия может быть потенциально быстрее, поскольку назначение условно.