Компилятор С++ оптимизирует эту операцию?
Мне хотелось бы верить, что да.
Компилятор С++ оптимизирует эту операцию?
Мне хотелось бы верить, что да.
Фактически VS2008 оптимизирует это для x + x:
01391000 push ecx
int x = 0;
scanf("%d", &x);
01391001 lea eax,[esp]
01391004 push eax
01391005 push offset string "%d" (13920F4h)
0139100A mov dword ptr [esp+8],0
01391012 call dword ptr [__imp__scanf (13920A4h)]
int y = x * 2;
01391018 mov ecx,dword ptr [esp+8]
0139101C lea edx,[ecx+ecx]
В сборке x64 он еще более явчен и использует:
int y = x * 2;
000000013FB9101E mov edx,dword ptr [x]
printf("%d", y);
000000013FB91022 lea rcx,[string "%d" (13FB921B0h)]
000000013FB91029 add edx,edx
Это будут настройки оптимизации на "Максимизировать скорость" (/O2)
Эта статья из Раймонда Чена может быть интересной:
Когда x/2 отличается от x → 1?: http://blogs.msdn.com/oldnewthing/archive/2005/05/27/422551.aspx
Цитата: Раймонд:
Конечно, компилятор может распознать это и переписать операцию умножения или сдвига. На самом деле, это очень вероятно, потому что x + x легче получить, чем умножение или сдвиг. Ваш сдвиг или умножение на два, вероятно, будет переписан как нечто более близкое к команде add eax, eax.
[...]
Даже если вы предполагаете, что сдвиг заполняется знаковым битом, результат сдвига и деления различны, если х отрицательный.
(- 1)/2 ≡ 0
(-1) → 1 ≡ -1[...]
Мораль этой истории - написать, что вы имеете в виду. Если вы хотите разделить на два, напишите "/2", а не " → 1".
Мы можем только предположить, что разумно рассказать компилятору, что вы хотите, а не то, что вы хотите от него: Компилятор лучше, чем человек, при оптимизации небольшого масштаба кода (спасибо Daemin чтобы указать на эту тонкую точку): если вы действительно хотите оптимизировать, используйте профилировщик и изучите эффективность своих алгоритмов.
VS 2008 оптимизировал шахту до x < 1.
x = x * 2;
004013E7 mov eax,dword ptr [x]
004013EA shl eax,1
004013EC mov dword ptr [x],eax
EDIT: это использовало конфигурацию по умолчанию "Отладка" по умолчанию с отключенной оптимизацией (/Od). Используя любой из оптимизационных переключателей (/O1,/O2 (VS "Retail" ), или /Ox ), появляется добавленный код self Rob. Кроме того, только для хорошей меры, я подтвердил, что x = x << 1
действительно рассматривается так же, как x = x * 2
компилятором cl в обоих /Od и/Ox. Итак, в заключение, cl.exe версии 15.00.30729.01 для x86 относится к * 2
и << 1
тождественно, и я ожидаю, что почти все другие компиляторы последнего времени сделают то же самое.
Нет, если x - это float, это не будет.
Да. Они также оптимизируют другие подобные операции, такие как умножение на не-силы двух, которые могут быть переписаны как суммы некоторых сдвигов. Они также оптимизируют деления по степеням 2 в правые смены, но будьте осторожны, что при работе со целыми целыми знаками две операции разные! Компилятор должен выпустить несколько дополнительных инструкций для сверления бит, чтобы убедиться, что результаты одинаковы для положительных и отрицательных чисел, но все же быстрее, чем выполнение разделения. Он также аналогично оптимизирует модули по степеням 2.
Ответ: "если он быстрее" (или меньше). Это зависит от целевой архитектуры, а также от модели использования регистра для данного компилятора. В общем, ответ "да, всегда", так как это очень простая оптимизация глазок, чтобы реализовать и обычно достойная победа.
Это только начало того, что оптимизаторы могут сделать. Чтобы узнать, что делает ваш компилятор, найдите переключатель, который заставляет его испускать источник ассемблера. Для компиляторов Digital Mars выходной ассемблер может быть проверен с помощью инструмента OBJ2ASM. Если вы хотите узнать, как работает ваш компилятор, то просмотр на выходе ассемблера может быть очень освещающим.
Я уверен, что все они делают такие оптимизации, но мне интересно, насколько они актуальны. Старые процессоры умножали на сдвиг и добавление, что может занять несколько циклов. С другой стороны, у современных процессоров есть набор баррель-переключателей, которые могут делать все необходимые сдвиги и дополнения одновременно за один такт или меньше. Кто-нибудь на самом деле сравнивает, действительно ли помогают эти оптимизации?
Да, они будут.
Если что-то не указано в стандарте языков, вы никогда не получите гарантированного ответа на такой вопрос. Если у вас есть сомнения, ваш компилятор выплюнул код сборки и проверил. Это будет единственный способ узнать.
@Ferruccio Barlettap >
Это хороший вопрос. Я отправился в Гуглинг, чтобы попытаться найти ответ.
Я не мог найти ответы на процессоры Intel напрямую, но эта страница имеет тот, кто пытался что-то время. Он показывает, что сдвиги будут более чем в два раза быстрее, чем реклама и умножаются. Бит сдвиги настолько просты (где умножение может быть сдвигом и добавлением), что это имеет смысл.
Итак, я разобрался с AMD и нашел старое руководство по оптимизации для Athlon с 2002 года, в котором перечислены самые быстрые способы умножения чисел на группы от 2 до 32. Интересно, что это зависит от числа. Некоторые из них - реклама, некоторые смены. Это на стр. 122.
Руководство для Athlon 64 показывает то же самое (стр. 164 или около того). Он говорит, что умножения - это 3 (в 32-битных) или 4 (в 64-битных) циклах, где сдвиги равны 1 и добавляются 2.
Кажется, он по-прежнему полезен как оптимизация.
Игнорируя количество циклов, этот метод может помешать вам связать блоки выполнения умножения (возможно), поэтому, если вы делаете много умножений в узком цикле, где некоторые используют константы, а некоторые не используют дополнительное планирование комната может быть полезна.
Но эта спекуляция.
Это зависит от того, какой у вас компилятор. Например, Visual С++, как известно, плохо оптимизирован. Если вы отредактируете сообщение, чтобы сказать, какой компилятор вы используете, было бы легче ответить.