То, что сказал ваш учитель, было косвенным утверждением без особых пояснений. Это НЕ то, что уменьшение происходит быстрее, чем увеличение, но вы можете создать гораздо более быстрый цикл с уменьшением, чем с приращением.
Не вдаваясь в подробности, без использования счетчика циклов и т. Д. - ниже важны только скорость и количество циклов (ненулевое).
Вот как большинство людей реализуют цикл с 10 итерациями:
int i;
for (i = 0; i < 10; i++)
{
//something here
}
В 99% случаев это все, что может понадобиться, но наряду с PHP, PYTHON, JavaScript существует целый мир критичного ко времени программного обеспечения (обычно встроенного, ОС, игр и т. Д.), Где тики процессора действительно имеют значение, поэтому кратко ознакомьтесь с кодом сборки:
int i;
for (i = 0; i < 10; i++)
{
//something here
}
после компиляции (без оптимизации) скомпилированная версия может выглядеть так (VS2015):
-------- C7 45 B0 00 00 00 00 mov dword ptr [i],0
-------- EB 09 jmp labelB
labelA 8B 45 B0 mov eax,dword ptr [i]
-------- 83 C0 01 add eax,1
-------- 89 45 B0 mov dword ptr [i],eax
labelB 83 7D B0 0A cmp dword ptr [i],0Ah
-------- 7D 02 jge out1
-------- EB EF jmp labelA
out1:
Весь цикл состоит из 8 инструкций (26 байт). В нем - фактически 6 инструкций (17 байт) с 2 ветвями. Да, да, я знаю, что это можно сделать лучше (это просто пример).
Теперь рассмотрим эту частую конструкцию, которую вы часто найдете написанной встроенным разработчиком:
i = 10;
do
{
//something here
} while (--i);
Он также повторяется 10 раз (да, я знаю, что значение i отличается от показанного в цикле for, но здесь мы заботимся о количестве итераций). Это может быть скомпилировано в это:
00074EBC C7 45 B0 01 00 00 00 mov dword ptr [i],1
00074EC3 8B 45 B0 mov eax,dword ptr [i]
00074EC6 83 E8 01 sub eax,1
00074EC9 89 45 B0 mov dword ptr [i],eax
00074ECC 75 F5 jne main+0C3h (074EC3h)
5 инструкций (18 байт) и всего одна ветка. Фактически в цикле 4 инструкции (11 байтов).
Лучше всего то, что некоторые процессоры (включая x86 / x64-совместимые) имеют инструкцию, которая может уменьшать регистр, позже сравнивать результат с нулем и выполнять переход, если результат отличен от нуля. Практически ВСЕ процессоры ПК реализуют эту инструкцию. Используя его, цикл фактически представляет собой одну (да, одну) 2-байтовую инструкцию:
00144ECE B9 0A 00 00 00 mov ecx,0Ah
label:
// something here
00144ED3 E2 FE loop label (0144ED3h) // decrement ecx and jump to label if not zero
Мне нужно объяснять, что быстрее?
Теперь, даже если конкретный процессор не реализует указанную выше инструкцию, все, что требуется для эмуляции, это декремент с последующим условным переходом, если результат предыдущей инструкции оказывается нулевым.
Итак, независимо от некоторых случаев, которые вы можете указать в качестве комментария, почему я ошибаюсь, и т. Д., Я ПОДЧЕРКНУЮ - ДА, ВЫГОДНО ПЕРЕЙТИ ВНИЗ, если вы знаете, как, почему и когда.
PS. Да, я знаю, что мудрый компилятор (с соответствующим уровнем оптимизации) перепишет цикл for (с возрастающим счетчиком цикла) в эквивалент do .. while для итераций постоянного цикла ... (или развернет его) ...