Как правило, циклы, которые считают до нуля, быстрее, чем циклы, которые считаются до некоторого другого числа. Я могу представить себе ситуацию, когда компилятор не может сделать эту оптимизацию за вас, но вы можете сделать это сами.
Скажем, у вас есть массив длины x, где x - очень большое число, и что вам нужно выполнить некоторую операцию с каждым элементом x. Далее, допустим, вам все равно, в каком порядке происходят эти операции. Вы можете сделать это ...
int i;
for (i = 0; i < x; i++)
doStuff(array[i]);
Но вы могли бы немного оптимизировать, сделав это таким образом -
int i;
for (i = x-1; i != 0; i--)
{
doStuff(array[i]);
}
doStuff(array[0]);
Компилятор не делает этого за вас, потому что не может предполагать, что порядок не важен.
Код примера MaR лучше. Учтите это, предполагая, что doStuff () возвращает int:
int i = x;
while (i != 0)
{
--i;
printf("%d\n",doStuff(array[i]));
}
Это нормально, если допустима печать содержимого массива в обратном порядке, но компилятор не может решить это за вас.
Эта оптимизация зависит от оборудования. Из того, что я помню о написании ассемблера (много-много лет назад), счет вверх, а не обратный отсчет до нуля, требует дополнительной машинной инструкции каждый раз, когда вы проходите цикл.
Если ваш тест похож на (x ‹y), тогда оценка теста будет примерно такой:
- вычесть y из x, сохраняя результат в некотором регистре r1
- test r1, чтобы установить флаги n и z
- ветвление на основе значений флагов n и z
Если ваш тест (x! = 0), вы можете сделать это:
- test x, чтобы установить флаг z
- ветвление на основе значения флага z
Вы можете пропустить инструкцию вычитания для каждой итерации.
Существуют архитектуры, в которых вы можете заставить команду вычитания устанавливать флаги на основе результата вычитания, но я почти уверен, что x86 не входит в их число, поэтому большинство из нас не используют компиляторы, у которых есть доступ к такой машинная инструкция.
person
Community
schedule
21.01.2010