Очень распространенный паттерн в программировании — ограничение максимального значения после некоторого обновления. Что я хотел бы знать, так это то, есть ли разница между следующими двумя частями кода и какой из них предпочтительнее:
value += increment;
value = std::min(value, valueMax);
против
value += increment;
if (value > valueMax)
value = valueMax;
Я думаю, что это сводится к тому, есть ли у процессоров инструкции для принятия двух значений и получения минимума. Если это так, вызов std :: min должен привести к этой инструкции и избежать ненужной ветви. Если нет, вторая версия избегает ненужного присваивания, когда значение <= значение Макс.
Я не очень хорош в таких вещах, но я уверен, что есть хакеры из старой школы, которые бы знали об этом. Им я спрашиваю: что лучше?
Современные компиляторы достаточно умны, чтобы генерировать один и тот же код в обоих случаях. Например, 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
На VC10 на выпуске для следующего кода у нас есть следующая сборка:
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
заявление. Это оптимизировано, и это более читабельно.
Ответ зависит от типа значения. Код может быть эффективно оптимизирован, если все операции полностью прозрачны для оптимизатора кода, что будет в случае, если значение является простым целым числом. Но ваш код также будет компилироваться, если значением является std :: string, и тогда вторая версия может быть потенциально более быстрой, поскольку присваивание является условным.