2009-05-26 23 views
24

Variable x ist int mit möglichen Werten: -1, 0, 1, 2, 3. Welche Ausdruck wird schneller (in CPU Ticks):Was ist schneller (x <0) oder (x == -1)?

1. (x < 0) 
2. (x == -1) 

Sprache: C/C++, aber ich denke, alle anderen Sprachen wird das gleiche haben.

P.S. Ich persönlich denke, dass die Antwort (x < 0) ist.

Allgemeiner für Gurus: Was wäre wenn x von -1 bis ?

+8

Um auf solche niedrigen Ebenen Überlegungen zu beantworten, wäre die CPU-Architektur ein minimaler Teil von Informationen, meinst du nicht? Aber selbst dann wäre eine CPU, die für diese Bedingungen eine unterschiedliche Anzahl von Zyklen benötigt, ziemlich primitiv. – joelr

+2

Auf jeder einigermaßen modernen CPU (innerhalb des letzten Jahrzehnts oder so) würde ich überrascht sein, wenn jeder 32-Bit-Ganzzahlvergleich mehr als einen Zyklus benötigte. – Eddie

+16

Warum ist das eine schlechte Frage? Eine gründliche Antwort davon lässt alles mit einem viel besseren Verständnis der Funktionsweise von Prozessoren und solchen Dingen einhergehen. Ist das nicht gut? –

Antwort

77

, die vollständig auf dem ISA hängt für Sie zusammenzustellen, und die Qualität des Compilers des Optimierers. Nicht vorzeitig optimieren: Profil zuerst, um Ihre Engpässe zu finden.

Das heißt, in x86 werden Sie feststellen, dass beide in den meisten Fällen gleich schnell sind. In beiden Fällen haben Sie einen Vergleich (cmp) und einen bedingten Sprung (jCC) Anweisungen. Jedoch kann es für (x < 0) einige Fälle geben, in denen der Compiler die cmp-Anweisung beenden kann, indem er Ihren Code um einen ganzen Zyklus beschleunigt.

Insbesondere dann, wenn der Wert x in einem Register gespeichert ist, und vor kurzem war das Ergebnis einer Rechenoperation (wie add oder sub, aber es gibt viele andere Möglichkeiten), die den Vorzeichen-Flag SF in den EFLAGS Registersatz, dann gibt es keine Notwendigkeit für die cmp Anweisung, und der Compiler kann nur eine js Anweisung ausgeben. Es gibt keine einfache jCC Anweisung, die springt, wenn die Eingabe -1 ist.

+21

Ich glaube nicht, dass dies der "Flaschenhals" in irgendeinem Programm ist oder war. Wenn Sie einen Unterschied in der Zeit gesehen haben, ist es wahrscheinlicher, dass Sie "springen" über die == -1 Bedingung, z. Setzen Sie es auf -2 und beendete damit die Schleife nicht (vorausgesetzt, dass Ausdruck Teil einer Schleife war). – lothar

+5

Vergessen Sie nicht, dass die cmp-Anweisung möglicherweise durch eine Anweisung oder ersetzt wird, wodurch die Anzahl der Zyklen nicht verringert wird, die Speicherausrichtung jedoch geändert werden kann. Dies könnte hilfreich sein oder kontraproduktiv sein, weshalb Profiling so wichtig ist. –

+16

P.S. Schauen Sie nicht auf diese Frage - ich hatte Schleifen, die so eng waren, dass diese Art der Optimierung einen Unterschied machen würde. Normalerweise nur ein paar Prozent, aber jedes bisschen hilft manchmal! –

1

Das gleiche, beide Operationen sind in der Regel in 1 Uhr erledigt.

+0

Es wäre ein Befehlsabruf- und Ausführungszyklus, aber kein Taktzyklus. – raimue

7

Beide Vorgänge können in einem einzigen CPU-Schritt ausgeführt werden, daher sollten sie die gleiche Leistung aufweisen.

+8

Arrrghh!Während dies bei der überwiegenden Mehrheit der Chips der Fall ist, können Sie einfach * keine definitive Aussage treffen, ohne die Plattform zu kennen, an der er arbeitet. Die ganze Welt ist kein x86. – dmckee

+2

nur das meiste davon;) –

+3

Nun, ich würde annehmen, wenn er diese Frage für eine bestimmte, nicht-normale Architektur stellte, würde er als solche angeben. Wenn er allgemein fragt, habe ich versucht, eine einfache Antwort für die meisten modernen Architekturen zu geben. –

23

Warum? Was auch immer Sie tun, der Compiler wird es auf jeder Plattform optimieren, auf der Sie gerade kompilieren.

Wenn Sie überprüfen müssen, ob es -1 ist, verwenden Sie (x == -1), wenn Sie wissen möchten, ob es weniger als Null ist, verwenden Sie stattdessen dieses. Schreibe was du laut vorlesen würdest.

Kleine Dinge wie diese werden nichts schneller machen, und Sie sollten sich Sorgen über Lesbarkeit und sauberes Design machen, anstatt welche winzige Operation schneller ist.

Und auch wenn es keine logischen Änderungen vornimmt, sind die Chancen auf Ihrer Plattform, beide in einem CPU-Zyklus ausgeführt werden.

+0

Danke. Es ist tatsächlich Engpass-Operator im Hochlastprogramm. Leistung in diesen 1-2 Strings ist viel wertvoller als Lesbarkeit und ich kann immer // Kommentare schreiben. –

+8

Wenn Sie bemerkenswerte Leistungszuwächse von etwas so Geringem haben, besteht die Möglichkeit, dass Ihr Design Refactoring benötigt (geeignetere Algorithmen). Aber wie andere gesagt haben, profilieren Sie es, um herauszufinden, für Ihre aktuelle Situation. – GManNickG

+4

Alle Engpässe sind normalerweise so klein, sogar in perfektem Design mit perfekten Algorithmen (obwohl es keine gibt). Ich lade DNA-Prozesse hoch und kenne mein Gebiet und meine Algorithmen recht gut. –

3

Die wichtige Überlegung ist sowieso, die tatsächlich Ihren Programmablauf genau leitet, und das gerade passiert, um das gleiche Ergebnis zu produzieren?

Wenn x tatsächlich und Index oder ein Wert in einer Enum ist, dann wird -1 immer was Sie wollen, oder wird ein negativer Wert arbeiten? Gerade jetzt, -1 ist der einzige Nachteil, aber das könnte sich ändern.

11

Probieren Sie es aus und sehen Sie! Machen Sie eine Million oder besser, eine Milliarde von jedem und Zeit sie. Ich wette, es gibt keine statistische Signifikanz in Ihren Ergebnissen, aber wer weiß - vielleicht finden Sie auf Ihrer Plattform und Ihrem Compiler vielleicht ein Ergebnis.

Dies ist ein großartiges Experiment, um sich davon zu überzeugen, dass eine vorzeitige Optimierung Ihre Zeit wahrscheinlich nicht wert ist - und möglicherweise "the root of all evil--at least in programming" lautet.

+1

Das ist ein Ratschlag, aber nicht wirklich eine Antwort. –

2

Sie können diese Frage nicht aus dem Zusammenhang heraus beantworten. Wenn Sie einen trivialen-Micro versuchen, dann ist es durchaus möglich, dass der Optimierer den Code in den Äther wehen wird:

// Get time 
int x = -1; 
for (int i = 0; i < ONE_JILLION; i++) { 
    int dummy = (x < 0); // Poof! Dummy is ignored. 
} 
// Compute time difference - in the presence of good optimization 
// expect this time difference to be close to useless. 
+0

Es wird von Compiler in Null-Anweisungen optimiert. Aber ich habe deine Idee verstanden, danke. –

+0

Ja - das habe ich auf eine fröhliche Weise versucht zu sagen. Wenn es beim ersten Versuch nicht klar war, meine Schuld. –

+0

Sie können dies bis zu einem gewissen Grad vermeiden, indem Sie x und dummy erlauben zu entkommen (dh ihre Zeiger auf eine Funktion in einer anderen Übersetzungseinheit zu übergeben) und einen Compiler-spezifischen Speicherbarrierenbefehl wie gcc's __sync_synchronize() einführen. Dies zwingt den Compiler, Code auszugeben, um auszuwerten (x <0) und Dummy zu setzen - aber er wird auch Speicherzugriffe erzwingen. – bdonlan

7

Es könnte davon abhängig sein, welche Operationen dem Vergleich vorangehen oder folgen. Wenn Sie beispielsweise vor dem Vergleich einen Wert x zuweisen, ist es möglicherweise schneller, das Vorzeichen zu prüfen als mit einem bestimmten Wert zu vergleichen. Oder die Verzweigungsvorhersage-Leistung der CPU könnte durch den von Ihnen ausgewählten Vergleich beeinflusst werden.

Aber, wie andere gesagt haben, hängt dies von CPU-Architektur, Speicherarchitektur, Compiler und vielen anderen Dingen ab, also gibt es keine allgemeine Antwort.

+0

Danke, gute Antwort. –

7

x < 0 wird schneller sein. Nicht zuletzt verhindert es das Abrufen der Konstanten -1 als Operand. Die meisten Architekturen haben spezielle Anweisungen zum Vergleich gegen Null, so dass auch das helfen wird.

+2

Wie können Sie das sagen, ohne Architektur und/oder Compiler zu kennen? –

+1

Über welche Architektur sprichst du? Ich glaube, dass die meisten x86-Befehlssätze einen Vergleich mit einem unmittelbaren Wert durchführen können. Kein Bedarf, einen Operanden zu holen. Hier ist ein Link zu einer Intel Befehlssatz Referenz: http://www.intel.com/Assets/PDF/manual/253666.pdf – jabbie

+0

Sicher, fast jede Architektur kann einen Vergleich mit einem unmittelbaren Wert machen. Aber selbst dort ist der Befehl größer (und erfordert daher einen weiteren Abruf aus dem Speicher).Keine große Sache, es sei denn, jede einzelne Leistung ist kritisch, was hier der Kontext zu sein scheint. Ich nehme an, dass der Fragesteller einen Gerätetreiber oder etwas schreibt. –

1

Es hängt von der Architektur ab, aber das x == -1 ist fehleranfälliger. x < 0 ist der Weg zu gehen.

+1

Nein, das ist nicht der richtige Weg. Um Fehler zu erkennen, verwenden Sie Komponententests, kein schicker Code. Um weniger fehleranfällig zu sein: geben Sie Konstanten einen Namen. Es ist normalerweise besser, direkt auf den Punkt zu gehen. Wenn das Ziel ist, mit -1 zu vergleichen, schreibe einfach (x == -1), andernfalls muss der nächste Entwickler, der diesen Code verwaltet, herausfinden, warum wir mit 0 vergleichen ("Oh, ok, es ist tatsächlich, gegen zu testen -1 "), und dann herauszufinden, was (die f ...) ist -1. – Jem

+0

Nun, wir sprechen über einen Idealfall. Wie Sie sagen, sollte niemand "magische Zahlen", sondern Konstanten verwenden. Sie können auf diese Weise mit (x <= VALUE) vergleichen. Normalerweise machen Sie dies mit Zählervariablen, also ist es ein guter Weg, weniger fehleranfällig zu sein. In der Praxis kann der Komponententest nicht immer durchgeführt werden (Zeit oder andere Einschränkungen). Offensichtlich, wenn es ein spezieller Fall ist, wollen Sie nur den '-1' Wert überprüfen, (x == WERT) es ist der Weg zu gehen. –

1

Wie andere gesagt haben, gibt es wahrscheinlich keinen Unterschied. Vergleiche sind solche grundlegenden Operationen in einer CPU, die Chip-Designer so schnell wie möglich machen wollen.

Aber es gibt noch etwas, das Sie berücksichtigen könnten. Analysieren Sie die Häufigkeiten jedes Werts und führen Sie die Vergleiche in dieser Reihenfolge durch. Dies könnte Sie einige Zyklen sparen. Natürlich müssen Sie Ihren Code noch zu asm kompilieren, um dies zu überprüfen.

1

Ich bin sicher, Sie sind sich sicher, dass dies ein echter Zeitnehmer ist.

Ich würde annehmen, die Maschine würde eine zuverlässigere Antwort geben, als jeder von uns geben könnte.

Ich habe festgestellt, sogar in Code wie Sie sprechen, meine Annahme, dass ich wusste, wo die Zeit war nicht ganz richtig war. Zum Beispiel, wenn dies in einer inneren Schleife ist, wenn es irgendeine Art von Funktionsaufruf gibt, sogar eine unsichtbare, die vom Compiler eingefügt wurde, werden die Kosten dieses Aufrufs bei weitem dominieren.

1

Nikolay, schreiben Sie:

Es ist eigentlich Betreiber in die Hochlast-Programm Engpass. Performance in diese 1-2 Saiten ist viel wertvoller als Lesbarkeit ...

Alle Engpaß sind in der Regel dieses klein, auch in perfektem Design mit perfekten Algorithmen (obwohl es keine so).Ich mache mit hoher Last DNA Verarbeitung und weiß, dass mein Bereich und meine Algorithmen recht gut

Wenn ja, warum nicht als nächstes zu tun:

  1. erhalten Timer, setzen Sie ihn auf 0;
  2. kompilieren Sie Ihr Hochlastprogramm mit (x < 0);
  3. starten Sie Ihr Programm und Timer;
  4. am Programm Ende schauen Sie auf den Timer und merken Sie sich result1.
  5. wie 1;
  6. kompilieren Sie Ihr Hochlastprogramm mit (x == -1);
  7. wie 3;
  8. am Programmende schauen Sie auf den Timer und erinnern Sie sich result2.
  9. Vergleichen Sie result1 und result2.

Sie erhalten die Antwort.

Verwandte Themen