2015-01-05 8 views
5

Wenn ich eine Schleife habe, die ich n-mal ausführen muss, gibt es eine Möglichkeit, eine while (oder für) -Schleife ohne jedes Mal zu schreiben? Wenn nicht, ist es eine Möglichkeit, einen Makro wiederum zu machen:Schleife ohne Vergleich n-mal in C

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

in:

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

P. S. Dies ist die schnellste Schleife, die ich bisher entwickelt habe.

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

Das ist nichts, was Sie tun sollten. Ihr Compiler entrollt bereits Schleifen, wenn es effektiver ist. – ThiefMaster

+0

Warum möchten Sie das tun? Es wird mehr Platz im Befehlscache benötigen, mehr Dekodierung von Befehlen erfordern und grundsätzlich schlechter sein. Wenn es besser wäre, würde der Compiler es nicht für Sie konvertieren? (Es sei denn, es ist ein Stück Müll, in welchem ​​Fall warum verwenden Sie es?) –

Antwort

7

Ein Ausreichend Smart Compiler wird dies für Sie tun. Genauer gesagt, das Optimieren von Compilern versteht Schleifen-Abrollung. Es ist eine relativ einfache Optimierung, besonders in Fällen wie dem Beispiel, in dem die Anzahl der Iterationen zur Kompilierzeit bekannt ist.

Kurz gesagt: Aktivieren Sie Compiler-Optimierungen und machen Sie sich keine Sorgen.

0

beide Schleifen werden Vergleiche tun ..

trotzdem sollte der Compiler die Konstante Iteration identifizieren und die Schleife entrollen.

Sie könnten das mit gcc und den Optimierungsflags (-O) überprüfen und anschließend den generierten Code betrachten.

Wichtiger: Optimieren Sie nicht, es sei denn, es gibt einen wichtigen Grund zu tun!

5

Die Anzahl der Anweisungen, die Sie im Quellcode schreiben, bezieht sich nicht ausschließlich auf die Anzahl der Maschinenanweisungen, die der Compiler generiert.

Die meisten Compiler sind intelligenter und in Ihrem zweiten Beispiel kann wie Code erzeugen:

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

automatisch, weil sie erkennen, dass die Schleife immer 5-mal durchlaufen wird.

Auch wenn Sie tun, um eine Profilierung orientierte Optimierung und der Compiler sieht, dass eine Schleife hat winzige einen Körper und eine sehr hohe Wiederholungs zählen sie es sogar für eine generische Anzahl von Iterationen mit Code wie entrollen kann:

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

Dies wird für große count s etwa ein Fünftel der Tests im Vergleich zu der naiven Version machen.

Ob das wert ist oder nicht, ist etwas, was nur Profiling sagen kann.

Eine Sache, die Sie tun können, wenn Sie sicher sind, dass der Code ausgeführt werden muss, mindestens einmal ist

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

statt

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

Die Möglichkeit, zu schreiben, dass count==0 etwas ärgerlich für CPUs, da in dem von den meisten Compilern generierten Code ein zusätzlicher JMP-Forward erforderlich ist:

der Maschinencode für die do { ... } while Version stattdessen ist einfach

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

Sie können die letzte Schleife mit: 'switch (count) {case 4: operation(); Fall 3: Operation(); Fall 2: Operation(); Fall 1: Operation(); } ' – Marian

0

Sobald der C-Code kompiliert wird, die während und nach Schleifen Vergleich Aussagen in Maschinensprache umgewandelt werden, so gibt es keine Möglichkeit, irgendeine Art von zu vermeiden Vergleich mit den for/while-Schleifen. Sie könnten eine Reihe von goto- und arithmetischen Anweisungen erstellen, die vermeiden, einen Vergleich zu verwenden, aber das Ergebnis wäre wahrscheinlich weniger effizient. Sie sollten untersuchen, wie diese Schleifen mithilfe von radare2 oder gdb in die Maschinensprache übersetzt werden, um zu sehen, wie sie dort verbessert werden können.

0

Mit Vorlage, können Sie die Schleife entrollen (in der Zählung zum Zeitpunkt der Kompilierung bekannt ist) mit so etwas wie:

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

aber der Compiler kann bereits für normale diese Art von Optimierung tun Schleife.