it-swarm.com.de

Sollte man <oder <= in einer for-Schleife verwenden

Wenn Sie eine Schleife siebenmal durchlaufen müssten, würden Sie Folgendes verwenden:

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

oder:

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

Es gibt zwei Überlegungen:

  • performance
  • lesbarkeit

Für die Leistung gehe ich von Java oder C # aus. Ist es wichtig, ob "kleiner als" oder "kleiner als oder gleich" verwendet wird? Wenn Sie Einsicht in eine andere Sprache haben, geben Sie bitte an, welche .

Zur besseren Lesbarkeit gehe ich von 0-basierten Arrays aus.

PD: Meine Erwähnung von 0-basierten Arrays hat möglicherweise Verwirrung gestiftet. Ich spreche nicht über das Durchlaufen von Array-Elementen. Nur eine allgemeine Schleife.

Es gibt einen guten Grund, eine Konstante zu verwenden, um zu erklären, was diese magische Zahl ist. Wenn ich also "int NUMBER_OF_THINGS = 7" dann "i <= NUMBER_OF_THINGS - 1 "würde komisch aussehen, nicht wahr?.

124
Eugene Katz

Das erste ist mehr idiomatisch . Insbesondere gibt es (in einem 0-basierten Sinn) die Anzahl der Iterationen an. Wenn ich etwas 1-basiertes verwende (z. B. JDBC, IIRC), könnte ich versucht sein, <= zu verwenden. So:

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

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

Ich würde erwarten, dass der Leistungsunterschied im Code der realen Welt unbedeutend gering ist.

286
Jon Skeet

Beide Schleifen werden siebenmal wiederholt. Ich würde sagen, das mit einer 7 ist lesbarer/klarer, es sei denn, Sie haben einen wirklich guten Grund für das andere.

72
Steve Losh

Ich erinnere mich an meine Zeit als wir 8086 Assembly am College gemacht haben, war es performanter zu tun:

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

da es eine JNS -Operation gab, bedeutet dies Jump if No Sign. Dies bedeutete, dass nach jedem Zyklus kein Speicher-Lookup durchgeführt wurde, um den Vergleichswert zu erhalten, und auch kein Vergleich. Heutzutage optimieren die meisten Compiler die Registernutzung, so dass die Speichersache nicht mehr wichtig ist, Sie aber dennoch einen nicht benötigten Vergleich erhalten.

Übrigens: Wenn Sie 7 oder 6 in Ihre Schleife einfügen, wird eine " magische Zahl " eingefügt. Zur besseren Lesbarkeit sollten Sie eine Konstante mit einem aussagekräftigen Namen verwenden. So was:

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

BEARBEITEN: Die Leute bekommen die Versammlungssache nicht, daher ist natürlich ein ausführlicheres Beispiel erforderlich:

Wenn wir für (i = 0; i <= 10; i ++) tun, müssen Sie dies tun:

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

Wenn wir das für (int i = 10; i> -1; i--) tun, können Sie damit durchkommen:

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

Ich habe es gerade überprüft und der C++ - Compiler von Microsoft führt diese Optimierung nicht durch, aber wenn Sie dies tun:

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

Die Moral lautet also, wenn Sie Microsoft C++ † verwenden und Aufsteigend oder Absteigend keinen Unterschied macht, um eine schnelle Schleife zu erhalten, sollten Sie Folgendes verwenden:

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

anstatt einer von diesen:

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

Offen gesagt ist die Lesbarkeit von "for (int i = 0; i <= 10; i ++)" jedoch weitaus wichtiger als das Fehlen eines Prozessorbefehls.

† Andere Compiler können andere Dinge tun.

55
Martin Brown

Ich verwende immer <array.length, weil es einfacher zu lesen ist als <= array.length-1.

wenn Sie auch <7 haben und wissen, dass es mit einem 0-Index beginnt, sollte es intuitiv sein, dass die Anzahl die Anzahl der Iterationen ist.

27
Omar Kooheji

Aus einer optimierenden Sicht spielt es keine Rolle.

Vom Standpunkt des Codestils aus gesehen bevorzuge ich <. Grund:

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

ist so viel lesbarer als

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

mit <geben Sie die Anzahl der Iterationen sofort an.

Ein weiteres Votum für <ist, dass Sie möglicherweise viele versehentliche Fehler vermeiden.

18
erlando

@ Chris, Ihre Aussage, dass .Length in .NET teuer ist, ist tatsächlich falsch und im Fall von einfachen Typen ist genau das Gegenteil der Fall.

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

ist eigentlich langsamer als

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

Letzteres ist ein Fall, der durch die Laufzeit optimiert wird. Da die Laufzeit garantieren kann, dass i ein gültiger Index für das Array ist, werden keine Begrenzungsprüfungen durchgeführt. Im ersten Fall kann die Laufzeit nicht garantieren, dass ich vor der Schleife nicht geändert wurde, und erzwingt bei jeder Indexsuche eine Begrenzungsüberprüfung des Arrays.

10
Jeff Mc

Es macht keinen wirkungsvollen Unterschied, wenn es um Leistung geht. Daher würde ich das verwenden, was im Zusammenhang mit dem von Ihnen gelösten Problem leichter zu verstehen ist.

6
Phil Wright

Ich bevorzuge:

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

Ich denke, das bedeutet eher "7-maliges Durchlaufen einer Schleife".

Ich bin nicht sicher, was die Auswirkungen auf die Leistung angeht - ich vermute, dass Differenzen kompiliert würden.

5
Dominic Rodger

In Java 1.5 können Sie einfach tun

for (int i: myArray) {
    ...
}

für den Array-Fall brauchen Sie sich also keine Sorgen zu machen.

4
JesperE

Ich glaube nicht, dass es einen Leistungsunterschied gibt. Die zweite Form ist auf jeden Fall besser lesbar, Sie müssen sie jedoch nicht mental subtrahieren, um die letzte Iterationsnummer zu finden.

EDIT: Ich sehe, dass andere anderer Meinung sind. Für mich persönlich möchte ich die tatsächlichen Indexnummern in der Schleifenstruktur sehen. Vielleicht liegt es daran, dass es eher an Perls 0..6 Syntax, die ich weiß, entspricht (0,1,2,3,4,5,6). Wenn ich eine 7 sehe, muss ich den Operator daneben überprüfen, um festzustellen, dass der Index 7 tatsächlich nie erreicht wird.

4
Adam Bellaire

Ich würde sagen, verwenden Sie die "<7" -Version, da dies von der Mehrheit der Benutzer gelesen wird. Wenn Sie also Ihren Code überfliegen, wird er möglicherweise falsch interpretiert.

Ich würde mir keine Sorgen machen, ob "<" schneller ist als "<=".

Wenn Sie die Geschwindigkeit erhöhen möchten, beachten Sie Folgendes:

for (int i = 0; i < this->GetCount(); i++)
{
  // Do something
}

Um die Leistung zu steigern, können Sie sie leicht neu anordnen in:

const int count = this->GetCount();
for (int i = 0; i < count; ++i)
{
  // Do something
}

Beachten Sie die Entfernung von GetCount () aus der Schleife (da dies in jeder Schleife abgefragt wird) und die Änderung von "i ++" zu "++ i".

4
Mark Ingram

Edsger Dijkstra schrieb einen Artikel dazu 1982, wo er für unteres <= i <oberes argumentiert:

Es gibt eine kleinste natürliche Zahl. Ausschluss der Untergrenze - wie in b) und d) - zwingt für eine Teilfolge ab der kleinsten natürlichen Zahl die Untergrenze wie erwähnt in den Bereich der unnatürlichen Zahlen. Das ist hässlich, daher bevorzugen wir für die untere Schranke ≤ wie in a) und c). Betrachten Sie nun die Teilsequenzen, die bei der kleinsten natürlichen Zahl beginnen: Die Einbeziehung der oberen Schranke würde diese dann zwingen, unnatürlich zu sein, bis die Sequenz auf die leere geschrumpft ist. Das ist hässlich, also bevorzugen wir für die obere Schranke <wie in a) und d). Wir schließen daraus, dass die Konvention a) vorzuziehen ist.

4
Martijn

In C++ bevorzuge ich die Verwendung von !=, der mit allen STL-Containern verwendbar ist. Nicht alle STL-Container-Iteratoren sind weniger als vergleichbar.

4
madmoose

Verwenden Sie zuerst nicht 6 oder 7.

Besser zu benutzen:

int numberOfDays = 7;
for (int day = 0; day < numberOfDays ; day++){

}

In diesem Fall ist es besser als mit

for (int day = 0; day <= numberOfDays  - 1; day++){

}

Noch besser (Java/C #):

for(int day = 0; day < dayArray.Length; i++){

}

Und noch besser (C #)

foreach (int day in days){// day : days in Java

}

Die umgekehrte Schleife ist zwar schneller, aber da es schwieriger zu lesen ist (wenn nicht von Ihnen von anderen Programmierern), ist es besser, dies zu vermeiden. Insbesondere in C #, Java ...

3
Carra

Ich bin damit einverstanden, dass die 7 in diesem Fall Sinn macht, aber ich möchte hinzufügen, dass in dem Fall, in dem die 6 wichtig ist, Sie klar machen möchten, dass Sie nur auf Objekte bis zum 6. Index einwirken, dann auf den <= ist besser, da die 6 leichter zu sehen ist.

2
tloach

Auf dem College erinnere ich mich, dass diese beiden Vorgänge in der Rechenzeit auf der CPU ähnlich waren. Natürlich reden wir auf der Ebene der Versammlung.

Wenn Sie jedoch C # oder Java sprechen, glaube ich wirklich nicht, dass eine Geschwindigkeitssteigerung die andere übertrifft. Die wenigen Nanosekunden, die Sie gewinnen, sind höchstwahrscheinlich keine Verwirrung wert, die Sie einführen.

Persönlich würde ich den Code verfassen, der unter dem Gesichtspunkt der Geschäftsimplementierung sinnvoll ist, und sicherstellen, dass er leicht zu lesen ist.

2
casademora

Dies fällt direkt unter die Kategorie "Falschen Code falsch aussehen lassen" .

In nullbasierten Indizierungssprachen wie Java oder C #) sind die Benutzer an Variationen der Bedingung index < count Gewöhnt. Wenn Sie diese defacto-Konvention verwenden, treten daher Fehler auf noch offensichtlicher.

In Bezug auf die Leistung: Jeder gute Compiler, der seinen Speicherbedarf wert ist, sollte so etwas wie ein No-Issue rendern.

2
Ryan Delucchi

Nebenbei bemerkt, wenn ich ein Array oder eine andere Sammlung in .Net durchlaufe, finde ich

foreach (string item in myarray)
{
    System.Console.WriteLine(item);
}

lesbarer sein als die numerische for-Schleife. Dies setzt natürlich voraus, dass der tatsächliche Zähler Int selbst nicht im Schleifencode verwendet wird. Ich weiß nicht, ob es eine Leistungsänderung gibt.

2
Rob Allen

Wenn Sie sich angewöhnen, <zu verwenden, wird dies sowohl für Sie als auch für den Leser konsistent, wenn Sie ein Array durchlaufen. Es wird für jeden einfacher sein, eine Standardkonvention zu haben. Und wenn Sie eine Sprache mit 0-basierten Arrays verwenden, ist <die Konvention.

Dies ist mit ziemlicher Sicherheit wichtiger als jeder Leistungsunterschied zwischen <und <=. Erst Funktionalität und Lesbarkeit anstreben, dann optimieren.

Ein weiterer Hinweis ist, dass es besser ist, ++ i anstelle von i ++ zu verwenden, da für das Abrufen und Inkrementieren ein temporäres Element und für das Inkrementieren und Abrufen kein Element erforderlich ist. Für Ganzzahlen wird Ihr Compiler wahrscheinlich die temporäre Abwesenheit optimieren, aber wenn Ihr iterierender Typ komplexer ist, ist dies möglicherweise nicht möglich.

1
JohnMcG

Sie könnten auch != stattdessen. Auf diese Weise erhalten Sie eine Endlosschleife, wenn Sie einen Fehler bei der Initialisierung machen, wodurch der Fehler früher bemerkt wird und alle Probleme, die er verursacht, darauf beschränkt werden, in der Schleife hängen zu bleiben (anstatt ein Problem viel später zu haben und nicht zu finden) es).

1
Brian

Verwenden Sie keine magischen Zahlen.

Warum ist es 7? (oder 6 für diese Angelegenheit).

verwenden Sie das richtige Symbol für die Nummer, die Sie verwenden möchten ...

In diesem Fall halte ich es für besser

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

Gute Frage. Meine Antwort: benutze Typ A ('<')

  • Sie sehen deutlich, wie viele Iterationen Sie haben (7).
  • Der Unterschied zwischen zwei Endpunkten ist die Breite des Bereichs
  • Weniger Zeichen machen es besser lesbar
  • Sie haben häufiger die Gesamtzahl der Elemente i < strlen(s) als den Index des letzten Elements , daher ist die Einheitlichkeit wichtig.

Ein weiteres Problem ist mit diesem ganzen Konstrukt. i erscheint mal darin, so dass es falsch geschrieben werden kann. Das for-Schleifenkonstrukt sagt wie zu tun ist anstelle von was zu tun ist. Ich schlage vor, dies zu übernehmen:

BOOST_FOREACH(i, IntegerInterval(0,7))

Dies ist klarer, kompiliert genau die gleichen asm-Anweisungen usw. Fragen Sie mich nach dem Code von IntegerInterval, wenn Sie möchten.

1

So viele Antworten ... aber ich glaube, ich habe etwas hinzuzufügen.

Ich bevorzuge, dass die Literalzahlen deutlich zeigen, welche Werte "i" in der Schleife annehmen. Im Falle einer Iteration durch ein nullbasiertes Array:

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

Und wenn Sie nur eine Schleife ausführen und kein Array durchlaufen, ist das Zählen von 1 bis 7 ziemlich intuitiv:

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

Die Lesbarkeit übertrifft die Leistung, bis Sie sie profilieren, da Sie wahrscheinlich nicht wissen, was der Compiler oder die Laufzeit mit Ihrem Code bis dahin tun wird.

1
Nick Westgate

Wie die Leute bemerkt haben, gibt es keinen Unterschied zwischen den beiden Alternativen, die Sie erwähnt haben. Um dies zu bestätigen, habe ich ein einfaches Benchmarking in JavaScript durchgeführt.

Sie können die Ergebnisse sehen hier . Daraus ist nicht ersichtlich, dass, wenn ich die Position des 1. und 2. Tests vertausche, die Ergebnisse für diese 2 Tests vertauschen, dies eindeutig ein Speicherproblem ist. Allerdings ist der 3. Test, bei dem ich die Reihenfolge der Iteration umkehre, deutlich schneller.

1
David Wees

Es gibt viele gute Gründe, i <7 zu schreiben. Es ist gut, die Nummer 7 in einer Schleife zu haben, die sieben Mal wiederholt wird. Die Leistung ist praktisch identisch. Fast jeder schreibt i <7. Wenn Sie aus Gründen der Lesbarkeit schreiben, verwenden Sie das Formular, das jeder sofort erkennt.

1
DJClayworth

Wie jeder sagt, ist es üblich, 0-indizierte Iteratoren auch für Dinge außerhalb von Arrays zu verwenden. Wenn alles beginnt um 0 und endet um n-1 und Untergrenzen sind immer <= und obere Schranken sind immer < gibt es so viel weniger zu denken, dass Sie tun müssen, wenn Sie den Code überprüfen.

1
ephemient

Die Operatoren '<' und '<=' sind genau die gleichen Leistungskosten.

Der Operator '<' ist ein Standard und in einer nullbasierten Schleife einfacher zu lesen.

Die Verwendung von ++ i anstelle von i ++ verbessert die Leistung in C++, jedoch nicht in C #. Ich kenne Java nicht.

1
Jeff B

Ich habe es immer vorgezogen:

for ( int count = 7 ; count > 0 ; -- count )
1
kenny

Kein Geschwindigkeitsunterschied, aber <ist in einer Sprache mit 0-basierten Arrays mit größerer Wahrscheinlichkeit korrekt. Wenn Sie nach unten anstatt nach oben iterieren möchten, können Sie außerdem Folgendes sagen:

for (i = 7; --i >= 0; ) ...
0
Mike Dunlavey

Zumindest bei den x86-Compilern sollte dies kein Leistungsunterschied sein. JL und JLE arbeiten zur gleichen Zeit, sobald ich weiß. In Bezug auf die Redability ist die Verwendung von "<7" für ein Array von sieben Elementen sinnvoll.

0
akalenuk

Ich würde behaupten, es sollte sein.

Warum viele Wörter verwenden, wenn ein paar ausreichen. Ein Test ist einfacher zu verstehen als zwei. Infolgedessen ist es einfacher, Einheiten zu testen und in Zukunft zu ändern.

Ist der Unterschied gering? Ja. Aber warum sollte man Komplexität hinzufügen, wenn dies nicht gerechtfertigt ist?.

Schließlich sind Sie nicht auf Optimierer oder die Implementierung eines Interpreters angewiesen, wenn der Code zu Beginn optimiert wird. Um Einstein zu zitieren, "halte es so einfach wie möglich, aber nicht einfacher".

0
Cam Wolff

Ich folge der ersten Methode, da diese Redewendung häufig wiederholt wird.

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

String s = oldString.substring (0, numChars);

etc.

Ich bin es gewohnt, dass die Obergrenze ausgeschlossen wird, und würde es vorziehen, dies so zu halten, es sei denn, es gibt einen guten Grund, dies zu ändern. (Beispiel - 1-basierte Indizierung)

0
Chris Cudmore

Prüfen Sie zuerst die Lesbarkeit und optimieren Sie sie später (obwohl ich mir ehrlich gesagt keinen merklichen Unterschied vorstellen kann).

Beachten Sie, dass die 0 -> K-Form ein C-Idiom ist, das in C # übertragen wird, indem Arrays auf 0 basieren. Befolgen Sie die Redewendung und verletzen Sie nicht den Grundsatz des geringsten Erstaunens.

0
plinth

Ich bevorzuge das:

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

Allerdings (dies ist nur ein Gedanke) muss die Lesbarkeit davon möglicherweise abhängen, ob Arrays 0-basiert (C #, Java) oder 1-basiert (VB .NET) sind. Ich sage dies, weil Sie bei der Arbeit mit 0-basierten Arrays die Einstellung haben, dass 0-6 7-mal ausgeführt wird. Ich denke, 0-6 ist intuitiver als 1-7. Andererseits komme ich aus C++, Java, C #.

0
Ryan Rodemoyer

Bei einigen Sprachen/Technologien wie .NET ist die Verwendung von .Size oder .Length oder size ()/length () eine schlechte Idee, da bei jeder Iteration auf diese Eigenschaft zugegriffen wird. Wenn sie einer Variablen zugewiesen wird, ist die Leistung etwas geringer.

0
Chris S

Ich denke, entweder sind in Ordnung, aber wenn Sie gewählt haben, bleiben Sie bei der einen oder der anderen. Wenn Sie es gewohnt sind, <= zu verwenden, versuchen Sie, <nicht zu verwenden und umgekehrt.

Ich bevorzuge <=, aber in Situationen, in denen Sie mit Indizes arbeiten, die bei Null beginnen, würde ich wahrscheinlich versuchen, <zu verwenden. Es ist jedoch alles persönliche Präferenz.

0
seanyboy

Streng genommen muss man denken, dass < count wäre effizienter als <= count aus dem genauen Grund, dass <= wird auch auf Gleichheit prüfen.

0
Henry B

Vorzeitige Optimierung ist die Wurzel allen Übels. Entscheiden Sie sich für Lesbarkeit, es sei denn, es gibt einen guten Grund, sich um < Gegenüber <= Sorgen zu machen.

0
cciotti