2015-01-05 3 views
5

Если у меня есть цикл, который, как мне известно, должен выполняться n раз, есть способ написать цикл while (или for) без сравнения каждый раз? Если нет, есть ли способ сделать макро поворот:Петля без сравнения n раз в C

int i = 0; 
for(i = 0; i < 5; i++) { 
    operation(); 
} 

в:

operation(); 
operation(); 
operation(); 
operation(); 
operation(); 

P.S. Это самый быстрый цикл, к которому я пришел.

int i = 5; 
while(i-- >= 0) { 
    operation(); 
} 
+4

Это ничего не должно делать. Ваш компилятор уже разворачивает циклы, если он более эффективен. – ThiefMaster

+0

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

ответ

7

A Достаточно Smart Compiler сделает это за вас. Более конкретно, оптимизация компиляторов понимает разворот цикла. Это довольно простая оптимизация, особенно в таких случаях, как ваш пример, когда количество итераций известно во время компиляции.

Итак, кратко: включите оптимизацию компилятора и не беспокойтесь об этом.

0

обе петли будет делать сравнение ..

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

Вы можете проверить это с помощью gcc и флажков оптимизации (-O) и затем просмотреть сгенерированный код.

Важнейшее значение: Не оптимизируйте, если нет существенных оснований!

5

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

Большинство компиляторов умнее и в вашем втором примере, может генерировать код, как:

operation(); 
operation(); 
operation(); 
operation(); 
operation(); 

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

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

while (count >= 5) { 
    operation(); 
    operation(); 
    operation(); 
    operation(); 
    operation(); 
    count -= 5; 
} 
while (count > 0) { 
    operation(); 
    count--; 
} 

Это составит для большой count s примерно одну пятую тестов по сравнению с наивной версией.

Если это стоит того или нет, это то, что может рассказать только профилирование.

Одна вещь, которую вы можете сделать, если вы уверены, что код должен быть выполнен по крайней мере один раз, чтобы написать

do { 
    operation(); 
} while (--count); 

вместо

while (count--) { 
    operation(); 
} 

вероятность того, что count==0 несколько раздражает для процессоров, потому что в коде, генерированном большинством компиляторов, требуется дополнительный JMP:

jmp test 
loop: 
    ...operation... 
test: 
    ...do the test... 
    jne loop 

машинный код для do { ... } while версии вместо просто

loop: 
    ... opertion ... 
    ... do the test... 
    jne loop 
+0

Вы можете развернуть последний цикл с помощью: 'switch (count) {case 4: operation(); кейс 3: операция(); кейс 2: операция(); case 1: operation(); } ' – Marian

0

После того, как код С скомпилирован, в то время как и циклов преобразуются в отчетность сравнения в машинном языке, так что нет никакого способа, чтобы избежать какого-то типа сравнение с петлями for/while. Вы можете сделать серию операторов goto и арифметики, которые избегают использования сравнения, но результат, вероятно, будет менее эффективным. Вы должны изучить, как эти петли скомпилированы в машинный язык, используя radare2 или gdb, чтобы посмотреть, как они могут быть улучшены там.

0

С шаблоном, вы можете развернуть цикл (в кол известно во время компиляции) с чем-то вроде:

namespace detail 
{ 

    template <std::size_t ... Is> 
    void do_operation(std::index_sequence<Is...>) 
    { 
     std::initializer_list<std::size_t>{(static_cast<void>(operation()), Is)...}; 
    } 

} 

template <std::size_t N> 
void do_operation() 
{ 
    detail::do_operation(std::make_index_sequence<N>()); 
} 

Live demo

но компилятор может уже сделать что-то оптимизации для нормальной петля.

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