2009-06-22 3 views
44

Я знаю, что это микро-оптимизация, поэтому я прошу из чистого любопытства.Является ли оператор неравенства быстрее, чем оператор равенства?

Логически, микропроцессор не должен сравнивать все биты обоих операндов оператора равенства, чтобы определить результат «FALSE».

Примечание. Это связано с программированием, поскольку оно влияет на скорость выполнения программы.

+4

Логически, микропроцессор не должен сравнивать все биты обоих операндов оператора равенства, чтобы определить результат «FALSE». –

+0

@ Джонатан Вакели. К сожалению. Спасибо что подметил это. Я отредактировал вопрос, чтобы исправить это. – Mackenzie

+2

Думаю, вы пропустили мою точку зрения, не заметив, что я сказал ** равенство ** и ** FALSE ** вместо ** неравенства ** и ** TRUE **. То, что я имел в виду, это то, что ЦП мог обнаружить два значения, не равные, не глядя на все биты, но неважно, используете ли вы '==' или '! =', Чтобы найти, что они не равны, поэтому оба оператора точно эквивалентны. Нет причин думать, что один быстрее, чем другой. –

ответ

35

Обычно микропроцессор выполняет сравнение с использованием электрических ворот, а не шаг за шагом. Он проверяет все биты сразу.

+3

Тем не менее, это будет зависеть от архитектуры, которую вы собираете. В общем случае cpu yes, это работает, но для встроенных микроконтроллеров сделать это не так просто. – NDEthos

2

Операция сравнения выполняется на восходящем (или, возможно, падающем) фронте тактового сигнала микропроцессора. Затем следующая операция выполняется в следующем такте. Таким образом, с точки зрения скорости выполнения, равенство и неравенство занимают одинаковое количество времени для почти каждого процессора на рынке сегодня.

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

+1

Вы говорите о невероятно простых процессорах по сравнению с современным CPUS. С современным процессором инструкции часто переупорядочиваются, выполняются одновременно, а несколько сразу удаляются (завершаются). Любые допущения, которые вы имеете о физическом порядке выполнения команд или недостатках между инструкциями, вероятно, слишком просты. В этом примере было бы очевидной потенциальной оптимизацией для того, чтобы CPU декодировал две инструкции, превратил их в один и выполнил в один такт. –

+0

er * недостатки -> зависимости. Кроме того, см. PDF-файл оптимизации из моего другого ответа для получения дополнительной информации. –

+0

OP специально упомянул о микропроцессорах, как и я. Мой плохой, если начинать с микропроцессора, то просто сказать, что процессор был неоднозначным. –

10

Сравнение обычно осуществляется как вычитание, которое игнорирует результат. Сумматор в CPU будет работать со всеми битами одновременно, так что это операция с постоянным временем.

Равенство тогда просто определяет, равен ли результат 0. На x86 существуют флаги, которые устанавливаются в результате сравнения, а ветвь выполняется через jz или jnz (скачок, если ноль, прыжок, если не ноль). Так что нет, не было бы реальной разницы в скорости.

Другие платформы (такие как ARM и IA64) ведут себя аналогичным образом.

1

Время, затрачиваемое на сравнение, как правило, представляет собой один такт.

32-разрядный процессор будет выполнять все 32 бита одновременно; 64-разрядный будет выполнять 64 бит одновременно.

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

25

Это зависит от платформы, но в целом она будет работать одинаково.

Например, на X86 вы можете увидеть это, посмотрев, как работает сборка. Посмотрите на X86 assembly control flow operations - независимо от того, выполняете ли вы равенство или неравенство, это делается как 2 операции.

Во-первых, вы выполняете операцию CMP (сравнение). Затем вы выполняете проверку, чтобы убедиться, что сравнение равно, не равно и т. Д. Это просто проверка результатов сравнения - в обоих случаях вы выполняете 2 операции.

Во многих языках программирования более высокого уровня, однако, все по-другому. Многие языки определяют неравенство в терминах равенства - чтобы проверить неравенство, проверите проверку равенства, затем вторую проверку, чтобы убедиться, что она ложна. Это приводит к тому, что на этих языках равенство (микроскопически) быстрее.Многие языки позволяют вам специально писать и то, и другое, но многие люди склонны писать неравенство с точки зрения равенства, что опять же делает равенство, в общем, несколько быстрее.

+1

В качестве дополнительного бонуса по сравнению с тем, чтобы узнать, равно ли значение равным 0, нет необходимости загружать значение, которое вы сравниваете с CPU. –

+0

@Tom - большинство ISA поддерживают немедленные значения, поэтому вы сравниваете с фиксированное значение должно быть таким же быстрым, как и ноль (есть исключения, конечно). – Michael

+0

@ Майкл в прежние времена x86 (и CISC в целом), немедленные нагрузки были все еще медленнее, чем сравнение с нулем (что обычно делалось с помощью чего-то вроде «AND ax, ax/JNZ tgt» или аналогичного). И в прежние времена RISC непосредственные значения поддерживались только в отдельной инструкции 'load', чтобы выполнить сравнение, но, по крайней мере, на MIPS,' $ 0' всегда было загружено значением 0. – fluffy

10

Похоже, вы должны прочитать Intel 64 and IA-32 Architectures Optimization Reference Manual.

Обратитесь к разделу «Задержка трубопровода» и «Задержка трубопровода» в инструкциях, которые вы используете. Достаточно сказать, что все, что вы делаете с ints, занимает около 1 такта, чтобы выполнить (4 миллиарда из них в секунду). Чтение данных из памяти может занять 100-1000 в зависимости от того, сколько данных вы работаете. Гораздо важнее.

2

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

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

+0

Это правда. Процессор в настоящее время предполагает, что ветви не принимаются, т. Е. Выполняется оператор if, без дополнительных подсказок. Компилятор может понять, что если это маловероятно, и структурируйте его по-разному/поставьте подсказку ветки. –

2

Есть несколько небольших случаев, когда это может иметь некоторый эффект.

На ARM-процессорах (для архитектуры набора инструкций 32-разрядной/не большой информации (ISA)) все команды являются условными. Иногда вы можете уйти с внутренним контуром, имеющим одну ветвь (от конца до начала), несмотря на множество условий. В нескольких случаях, имеющих логическое сравнение (TEQ), нарушается несколько флагов (влияет на отрицательные (N) и нулевые (Z), но не переносится (C) или переполнение (V)), позволяет волосатому коду избежать инструкции перехода (untaken).

И наоборот, IIRC (я его на самом деле не запрограммировал, но посмотрел вывод компилятора C более десяти лет назад). 68000 имеет буквальную инструкцию EOR/XOR только для регистра D4. Таким образом, арифметическое сравнение, вероятно, было бы лучше (хотя вы все равно могли игнорировать посторонние флаги - дело в том, что набор команд немного нерегулярный).

Как упоминалось предыдущим плакатом, большая часть действия выше с задержкой памяти, диска, сети и веб-сервисов.

1

Если вы хотите поднять это до более общего вопроса, вам нужно будет рассмотреть разумное распределение ответов TRUE и FALSE, и вам придется рассматривать произвольную длину слова, включая дольше, чем регистр.

В поисковых алгоритмах (и сортировка может рассматриваться как расширение поиска) чаще всего используются такие операторы, как «<» или «< =», чем «==». Это связано с тем, что распределение результатов от оператора «==» имеет тенденцию сильно искажаться в сторону «ложных» и, следовательно, имеет низкую энтропию (т. Е. Низкую информационную доходность) за выполнение. Это означает, что они должны выполняться больше раз, чтобы получить ту же информацию - наблюдать линейный поиск.

В любом случае они берут O (длина слова) числа бит-сравнений, хотя, если длина слова равна < = длина регистра, сравнения проводятся параллельно, возможно, небольшая задержка для переноса. (На самом деле, как я думаю об этом, в типичном неравном случае либо сравнение может остановиться на первом неравном бите, и если вероятность равенства достаточно мала, это может произойти довольно рано.)

1

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

Однако даже выше, используя оптимизацию опроса, работа будет работать в обоих направлениях. То есть равенство можно написать так же эффективно, как неравенство.

Кроме того, что касается людей, занимающихся сборкой, единственная разница между CMP и SUB - это какие флаги установлены. Они обычно выполняются с теми же частями машины, поскольку CMP должен возвращать флаги, которые представляют равенство, меньше и больше.

Смежные вопросы