c++ - Что быстрее: x<< 1 или x<< 10?



performance cpu (6)

Я не хочу ничего оптимизировать, клянусь, я просто хочу задать этот вопрос из любопытства. Я знаю, что на большинстве аппаратных средств есть команда сборки бит-сдвига (например, shl , shr ), которая является единственной командой. Но имеет ли значение (наносекундный, или процессорный такт), сколько бит вы сдвигаете. Другими словами, любой из них быстрее работает на любом процессоре?

x << 1;

а также

x << 10;

И, пожалуйста, не ненавидишь меня за этот вопрос. :)


В ARM это может быть сделано как побочный эффект другой команды. Так что потенциально, для любой из них нет никакой задержки.



На этом много случаев.

  1. Многие высокоскоростные MPU имеют баррель-сдвиг, мультиплексорную электронную схему, которая делает любой сдвиг в постоянное время.

  2. Если MPU имеет только 1 бит сдвига, x << 10 обычно будет медленнее, так как в основном это делается с помощью 10 сдвигов или байтов с 2 сменами.

  3. Но есть известный общий случай, когда x << 10 будет еще быстрее, чем x << 1 . Если x - 16 бит, только младшие 6 бит - это уход (все остальные будут сдвинуты), поэтому MPU необходимо загрузить только младший байт, таким образом, сделать только один цикл доступа к 8-разрядной памяти, тогда как x << 10 необходимо два цикла доступа. Если цикл доступа медленнее, чем сдвиг (и более чистый младший байт), x << 10 будет быстрее. Это может относиться к микроконтроллерам с быстрым встроенным программным ПЗУ при обращении к медленной внешней памяти данных.

  4. В дополнение к случаю 3 компилятор может заботиться о количестве значимых бит в x << 10 и оптимизировать дальнейшие операции для более низких значений, например, заменять умножение 16x16 на 16x8 (так как младший байт всегда равен нулю).

Обратите внимание, что некоторые микроконтроллеры вообще не имеют сдвиговой-левой инструкции add x,x вместо этого они вместо них add x,x .


Некоторые встроенные процессоры имеют только инструкцию «по очереди». На таких процессорах компилятор изменил бы x << 3 на ((x << 1) << 1) << 1 .

Я думаю, что Motorola MC68HCxx была одной из самых популярных семей с этим ограничением. К счастью, такие архитектуры сейчас довольно редки, большинство из них теперь включают в себя баррель-сдвиг с переменным размером сдвига.

Intel 8051, который имеет множество современных производных, также не может сдвигать произвольное количество бит.


Потенциально зависит от процессора.

Тем не менее, все современные процессоры (x86, ARM) используют «баррельный сдвиг» - аппаратный модуль, специально предназначенный для выполнения произвольных сдвигов в постоянное время.

Итак, нижняя строка ... нет. Нет разницы.


Это зависит как от процессора, так и от компилятора. Даже если базовый процессор имеет произвольный бит сдвига с помощью барреля, это произойдет, только если компилятор воспользуется этим ресурсом.

Имейте в виду, что перемещение чего-либо за пределами ширины в битах данных является «неопределенным поведением» в C и C ++. Правый сдвиг подписанных данных также определяется «реализацией». Вместо того, чтобы слишком сильно беспокоиться о скорости, будьте обеспокоены тем, что вы получаете одинаковый ответ на разные реализации.

Цитата из раздела ANSI C 3.3.7:

3.3.7 Операторы побитового сдвига

Синтаксис

      shift-expression:
              additive-expression
              shift-expression <<  additive-expression
              shift-expression >>  additive-expression

Ограничения

Каждый из операндов должен иметь интегральный тип.

Семантика

Интегральные рекламные акции выполняются на каждом из операндов. Тип результата - это продвинутый левый операнд. Если значение правого операнда отрицательное или больше или равно ширине в битах продвинутого левого операнда, поведение не определено.

Результат E1 << E2 - это E1 левые сдвиговые позиции E2; освобожденные биты заполняются нулями. Если E1 имеет неподписанный тип, значение результата будет E1, умноженное на величину 2, поднятую до мощности E2, уменьшенную по модулю ULONG_MAX + 1, если E1 имеет тип unsigned long, UINT_MAX + 1 в противном случае. (Константы ULONG_MAX и UINT_MAX определены в заголовке.)

Результатом E1 >> E2 является положение E1 с правой позицией E2. Если E1 имеет неподписанный тип, или если E1 имеет подписанный тип и неотрицательное значение, значение результата является неотъемлемой частью частного E1, деленной на величину 2, поднятую до степени E2. Если E1 имеет подписанный тип и отрицательное значение, результирующее значение определяется реализацией.

Так:

x = y << z;

«<<»: y × 2 z ( не определено, если происходит переполнение);

x = y >> z;

«>>»: реализация определена для подписанных (чаще всего результат арифметического сдвига: y / 2 z ).





low-level