Я потратил лет , настаивая на том, что любой разумный компилятор, достойный места на диске, оптимизирует num % 2 == 0
до num & 1 == 0
. Затем, проанализировав разборку по другой причине, у меня была возможность проверить мои предположения.
Оказывается, я был не прав. Microsoft Visual Studio , вплоть до версии 2013, генерирует следующий объектный код для num % 2 == 0
:
and ecx, -2147483647 ; the parameter was passed in ECX
jns SHORT $IsEven
dec ecx
or ecx, -2
inc ecx
$IsEven:
neg ecx
sbb ecx, ecx
lea eax, DWORD PTR [ecx+1]
Да, действительно. Это в режиме Release со всеми включенными оптимизациями. Вы получаете практически эквивалентные результаты, будь то сборка для x86 или x64. Вы, вероятно, не поверите мне; Я сам едва поверил в это.
Он делает то, что вы ожидаете от num & 1 == 0
:
not eax ; the parameter was passed in EAX
and eax, 1
Для сравнения GCC (начиная с версии 4.4) и Clang (начиная с версии 3.2) делают то, что можно было ожидать, генерируя идентичный объект код для обоих вариантов. Однако, согласно интерактивному компилятору Мэтта Годболта , ICC 13.0.1 также не поддается моим ожиданиям.
Конечно, эти компиляторы не неправильны . Это не ошибка. Есть много технических причин (как было указано в других ответах), почему эти два фрагмента кода не идентичны. И, безусловно, здесь следует привести аргумент «преждевременная оптимизация - зло». Конечно, есть причина, по которой мне потребовались годы, чтобы заметить это, и даже тогда я случайно наткнулся на нее.
Но, , как сказал Дуг Т. , вероятно, лучше определить где-нибудь в вашей библиотеке функцию IsEven
, которая исправит все эти маленькие детали, чтобы вам никогда не приходилось думать о них снова. - и держать ваш код читабельным. Если вы регулярно ориентируетесь на MSVC, возможно, вы определите эту функцию так, как я это сделал:
bool IsEven(int value)
{
const bool result = (num & 1) == 0;
assert(result == ((num % 2) == 0));
return result;
}