Следует ли использовать <или <= в цикле for - PullRequest
124 голосов
/ 08 октября 2008

Если бы вам пришлось повторять цикл 7 раз, вы бы использовали:

for (int i = 0; i < 7; i++)

или

for (int i = 0; i <= 6; i++)

Есть два соображения:

  • производительности
  • удобочитаемость

Для производительности я предполагаю Java или C #. Имеет ли значение, если используется «меньше» или «меньше или равно»? Если у вас есть понимание другого языка, укажите, какой.

Для удобства чтения я предполагаю массивы, основанные на 0.

UPD: Мое упоминание о массивах на основе 0 может привести к путанице. Я не говорю об итерации элементов массива. Просто общий цикл.

Ниже приведен хороший пункт об использовании константы, которая объясняет, что это за магическое число. Так что, если бы у меня было "int NUMBER_OF_THINGS = 7", то "i <= NUMBER_OF_THINGS - 1" выглядело бы странно, не правда ли.

Ответы [ 39 ]

286 голосов
/ 08 октября 2008

Первый больше идиоматический . В частности, оно указывает (в 0-значном смысле) количество итераций. При использовании чего-либо на основе 1 (например, JDBC, IIRC) у меня может возникнуть соблазн использовать <=. Итак: </p>

for (int i=0; i < count; i++) // For 0-based APIs

for (int i=1; i <= count; i++) // For 1-based APIs

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

72 голосов
/ 08 октября 2008

Оба этих цикла повторяются 7 раз. Я бы сказал, что тот, у которого 7, более читабелен / понятен, если только у вас нет веских причин для другого.

55 голосов
/ 08 октября 2008

Я помню, как в те дни, когда мы делали 8086 Ассамблею в колледже, это было более продуктивно:

for (int i = 6; i > -1; i--)

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

Между прочим, введение в цикл 7 или 6 вводит " магическое число ". Для лучшей читаемости вы должны использовать константу с намеренным раскрывающим именем. Как это:

const int NUMBER_OF_CARS = 7;
for (int i = 0; i < NUMBER_OF_CARS; i++)

РЕДАКТИРОВАТЬ: Люди не получают сборку, так что требуется более полный пример:

Если мы делаем для (i = 0; i <= 10; i ++), вам нужно сделать это: </p>

    mov esi, 0
loopStartLabel:
                ; Do some stuff
    inc esi
                ; Note cmp command on next line
    cmp esi, 10
    jle exitLoopLabel
    jmp loopStartLabel
exitLoopLabel:

Если мы сделаем для (int i = 10; i> -1; i--), то вы можете обойтись без этого:

    mov esi, 10
loopStartLabel:
                ; Do some stuff
    dec esi
                ; Note no cmp command on next line
    jns exitLoopLabel
    jmp loopStartLabel
exitLoopLabel:

Я только что проверил, и компилятор Microsoft C ++ не выполняет эту оптимизацию, но он делает, если вы делаете:

for (int i = 10; i >= 0; i--) 

Итак, если вы используете Microsoft C ++ †, и если возрастание или убывание не имеет значения, то для получения быстрого цикла вы должны использовать:

for (int i = 10; i >= 0; i--)

а не один из них:

for (int i = 10; i > -1; i--)
for (int i = 0; i <= 10; i++)

Но, откровенно говоря, получить читабельность «for (int i = 0; i <= 10; i ++)» обычно гораздо важнее, чем пропустить одну команду процессора. </p>

† Другие компиляторы могут делать разные вещи.

27 голосов
/ 08 октября 2008

Я всегда использую

также имея <7 и учитывая, что вы знаете, что он начинается с индекса 0, должно быть интуитивно понятно, что число - это число итераций. </p>

18 голосов
/ 08 октября 2008

С точки зрения оптимизации это не имеет значения.

С точки зрения стиля кода, который я предпочитаю <. Причина: </p>

for ( int i = 0; i < array.size(); i++ )

гораздо более читабельно, чем

for ( int i = 0; i <= array.size() -1; i++ )

также <дает вам количество итераций сразу. </p>

Еще один голос за <- это то, что вы можете предотвратить множество случайных ошибок. </p>

10 голосов
/ 08 октября 2008

@ Крис, Ваше утверждение о том, что .Leng является дорогостоящим в .NET, на самом деле не соответствует действительности, а в случае простых типов - полная противоположность.

int len = somearray.Length;
for(i = 0; i < len; i++)
{
  somearray[i].something();
}

на самом деле медленнее, чем

for(i = 0; i < somearray.Length; i++)
{
  somearray[i].something();
}

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

6 голосов
/ 08 октября 2008

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

5 голосов
/ 08 октября 2008

Я предпочитаю:

for (int i = 0; i < 7; i++)

Я думаю, что это более легко переводится как "повторение цикла 7 раз".

Я не уверен в последствиях для производительности - подозреваю, что любые различия будут компилироваться.

4 голосов
/ 09 октября 2008

Эдсгер Дейкстра написал статью об этом еще в 1982 году, где он утверждает, что нижний <= i <upper: </p>

Наименьшее натуральное число. Исключение нижней границы - как в b) и d) - силы для подпоследовательности, начинающейся с наименьшего натурального числа нижней границы, как упомянуто в область неестественных чисел. Это некрасиво, поэтому для нижней границы мы предпочитаем ≤ как в а) и в). Теперь рассмотрим подпоследовательности, начинающиеся с наименьшего натурального числа: включение верхней границы тогда заставило бы последнюю быть неестественной к тому времени, когда последовательность сократилась до пустой. Это некрасиво, поэтому для верхней границы мы предпочитаем <как в а) и г). Мы заключаем, что соглашение а) должно быть предпочтительным. </p>

4 голосов
/ 08 октября 2008

Я не думаю, что есть разница в производительности. Вторая форма определенно более удобна для чтения, вам не нужно мысленно вычитать ее, чтобы найти номер последней итерации.

РЕДАКТИРОВАТЬ: Я вижу, что другие не согласны. Лично я хотел бы видеть фактические номера индексов в структуре цикла. Возможно, это потому, что он больше напоминает синтаксис Perl 0..6, который, как я знаю, эквивалентен (0,1,2,3,4,5,6). Если я вижу 7, я должен проверить оператора рядом с ним, чтобы увидеть, что на самом деле индекс 7 никогда не достигается.

...