Ускоряет ли перестановка условной оценки цикл? - PullRequest
11 голосов
/ 09 апреля 2009

Немного странно: мой друг недавно сказал мне, что переставляет этот пример for loop from:

for(int i = 0; i < constant; ++i) {
    // code...
}

до:

for(int i = 0; constant > i; ++i) {
    // code...
}

немного увеличит производительность в C ++. Я не понимаю, как сравнение постоянного значения с переменной происходит быстрее, чем наоборот, и некоторые элементарные тесты, которые я выполнял, не показали разницы в скорости между двумя реализациями. То же самое относится и к тестированию этого цикла Python while:

while i < constant:
    # code...
    i += 1

против

while constant > i:
    # code...
    i += 1

Я не прав? Моих простых тестов недостаточно, чтобы определить изменение скорости? Это правда о других языках? Или это просто новая лучшая практика?

Ответы [ 13 ]

0 голосов
/ 09 апреля 2009

Я скромно полагаю, что на некоторых компиляторах на определенных архитектурах следующее может сократить более эффективно, чем варианты:

i = constant - 1
while (--i) {
}

Чтобы получить константу итераций.

Как отмечалось во многих комментариях, компилятор сделает хорошую работу по оптимизации цикла для вас (люди, занимающиеся оптимизацией компилятора, потратили много-много времени на размышления над этим). Разборчивый код, вероятно, более ценен, но YMMV!

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

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

Надежда, которая помогает и подбадривает.

0 голосов
/ 09 апреля 2009

Сегодня на хорошем компиляторе совсем нет.

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

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

Кроме того, не все платформы созданы равными. Встраиваемые платформы часто страдают от некондиционных оптимизаторов из-за низкой вычислительной мощности и требований к обработке в реальном времени.

На настольных / серверных платформах вес сместился в сторону хорошо инкапсулированной сложности, которая реализует лучшие алгоритмы масштабирования.

Микрооптимизации вредны только тогда, когда они вредят чему-то другому, например читабельности, сложности или ремонтопригодности. Когда все остальное равно, почему бы не выбрать быстрее?


Было время, когда завершение цикла в нуле (например, путем обратного отсчета) на x86 действительно могло дать заметные улучшения для тесных циклов, поскольку DEC CX/JCXNZ был быстрее (он все еще потенциально мог бы быть, так как мог сохранить регистр / доступ к памяти для сравнения; теперь оптимизация выполнения компилятора обычно выходит за рамки этого). То, что слышал твой друг, может быть искаженной версией этого.

0 голосов
/ 09 апреля 2009

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

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

...