5 Stimmen

Leistung von C++-Operatoren

Gibt es irgendeinen Leistungsunterschied zwischen den arithmetischen Operatoren in C++, oder laufen sie alle gleich schnell? Ist z.B. "++" schneller als "+=1"? Was ist mit "+=10000"? Macht es einen wesentlichen Unterschied, wenn es sich bei den Zahlen um Fließkommazahlen und nicht um ganze Zahlen handelt? Braucht "*" deutlich länger als "+"?

Ich habe versucht, jeweils 1 Milliarde "++", "+=1" und "+=10000" auszuführen. Das Seltsame ist, dass die Anzahl der Taktzyklen (laut time.h) eigentlich kontraintuitiv ist. Man könnte erwarten, dass "++" am schnellsten ist, gefolgt von "+=1" und dann "+=10000", aber die Daten zeigen einen leichten Trend in die entgegengesetzte Richtung. Bei 10 Milliarden Operationen ist der Unterschied noch deutlicher. Dies alles gilt für ganze Zahlen.

Ich beschäftige mich mit wissenschaftlichem Rechnen und wollte daher die Leistung der Operatoren testen. Wenn einer der Operatoren in einer Zeit arbeitet, die linear zu den Eingaben ist, zum Beispiel.

12voto

GManNickG Punkte 476445

Zu Ihrer Bearbeitung: Die Sprache sagt nichts über die Architektur aus, auf der sie läuft. Ihre Frage ist plattformabhängig.

Das heißt, alle grundlegenden Operationen vom Typ Daten haben in der Regel eine Eins-zu-Eins-Entsprechung zur Montage.

x86 hat zum Beispiel einen Befehl, der einen Wert um 1 erhöht, was i++ ou i += 1 würde das bedeuten. Auch für Addition und Multiplikation gibt es einzelne Anweisungen.

In Bezug auf die Hardware ist es ziemlich offensichtlich, dass das Addieren oder Multiplizieren von Zahlen mindestens linear zur Anzahl der Bits in den Zahlen ist. Da die Hardware eine konstante Anzahl von Bits hat, ist es O(1).

Fließkommazahlen haben in der Regel eine eigene Verarbeitungseinheit, die auch einzelne Anweisungen für Operationen hat.


Ist das wichtig?

Warum schreiben Sie nicht den Code, der das tut, was Sie brauchen? Wenn Sie eine hinzufügen wollen, verwenden Sie ++. Wenn Sie eine große Zahl addieren wollen, fügen Sie eine große Zahl hinzu. Wenn Sie Gleitkommazahlen benötigen, verwenden Sie Gleitkommazahlen. Wenn Sie zwei Zahlen multiplizieren müssen, dann multiplizieren Sie sie.

Der Compiler wird den besten Weg finden, das zu tun, was Sie wollen. Anstatt also zu versuchen, trickreich zu sein, tun Sie, was Sie brauchen, und lassen Sie ihn die harte Arbeit machen.

Nachdem Sie Ihren Arbeitscode geschrieben haben, stellen Sie fest, dass er zu langsam ist, Profil und finden Sie heraus, warum. Sie werden feststellen, dass es nicht an dummen Dingen wie Multiplizieren oder Addieren liegt, sondern daran, dass Sie das gesamte (Teil-)Problem auf die falsche Weise angehen.

Praktisch alle von Ihnen aufgeführten Operatoren werden auf Desktop-Plattformen ohnehin mit einem einzigen CPU-Befehl ausgeführt.

6voto

Pascal Cuoq Punkte 77147

Nein, nein, ja*, ja*, beziehungsweise.

* aber kümmert Sie das wirklich?

EDIT: Um eine Vorstellung von einem modernen Prozessor zu vermitteln, können Sie in der Zeit, die für einen Speicherzugriff benötigt wird, vielleicht 200 ganzzahlige Additionen und nur 50 ganzzahlige Multiplikationen durchführen. Wenn man darüber nachdenkt, wird man trotzdem die meiste Zeit durch die Speicherzugriffe gebunden sein.

4voto

pmr Punkte 56454

Was Sie fragen, ist: Welche Grundoperationen werden in welche Assembler-Befehle umgewandelt und wie ist die Leistung dieser Befehle auf meiner spezifischen Architektur. Und das ist auch Ihre Antwort: Der Code, in den sie übersetzt werden, hängt von Ihrem Compiler und dessen Kenntnis Ihrer Architektur ab, ihre Leistung hängt von Ihrer Architektur ab.

Wohlgemerkt: In C++ können Operatoren für benutzerdefinierte Typen überladen werden. Sie können sich anders verhalten als eingebaute Typen und die Implementierung der Überladung kann nicht trivial sein (nicht nur eine Anweisung).

Edit: Ein Hinweis zum Testen. Die meisten Compiler unterstützen die Ausgabe des erzeugten Assembler-Codes. Die Option für gcc ist -S. Wenn Sie einen anderen Compiler verwenden, werfen Sie einen Blick in dessen Dokumentation.

3voto

Richard Pennington Punkte 19289

Die beste Antwort ist, es mit Ihrem Compiler zu timen.

3voto

jalf Punkte 235501

Schauen Sie in den Optimierungshandbüchern für Ihre CPU nach. Das ist der einzige Ort, an dem Sie Antworten finden werden.

Bringen Sie Ihren Compiler dazu, die generierte Assembly auszugeben. Laden Sie die Handbücher für Ihre CPU herunter. Schlagen Sie die vom Compiler verwendeten Anweisungen im Handbuch nach, und Sie wissen, wie sie funktionieren.

Dies setzt natürlich voraus, dass Sie bereits die Grundlagen der Funktionsweise einer pipelinegesteuerten, superskalaren Out-of-Order-CPU kennen, wissen, was Verzweigungsvorhersage, Befehls- und Datencache und alles andere bedeutet. Machen Sie Ihre Hausaufgaben.

Leistung ist ein lächerlich kompliziertes Thema. Je nach Kontext kann Fließkomma-Code genauso schnell sein wie (oder schneller als) Integer-Code, oder er kann viermal langsamer sein. Normalerweise haben Verzweigungen so gut wie keinen Nachteil, aber in besonderen Fällen können sie lähmend wirken. Manchmal ist die Neuberechnung von Daten effizienter als deren Zwischenspeicherung, manchmal nicht.

Verstehen Sie Ihre Programmiersprache. Verstehen Sie Ihren Compiler. Verstehen Sie Ihre CPU. Und dann prüfen Sie genau, was der Compiler tut in Ihrem Fall , durch Profilierung/Zeitmessung und gegebenenfalls durch Prüfung der einzelnen Anweisungen. (und beim Timing Ihres Codes sollten Sie sich aller Vorbehalte und Probleme bewusst sein, die Ihre Benchmarks ungültig machen können: Vergewissern Sie sich, dass Optimierungen aktiviert sind, aber auch, dass der Code, den Sie zu messen versuchen, nicht wegoptimiert ist. Berücksichtigen Sie den Cache (wenn sich die Daten bereits im CPU-Cache befinden, läuft es viel schneller. Wenn die Daten erst aus dem physischen Speicher gelesen werden müssen, dauert es länger. Beides kann Ihre Messungen verfälschen, wenn Sie nicht vorsichtig sind. Denken Sie daran, was Sie genau messen wollen)

Warum sollten Sie bei Ihren konkreten Beispielen ++i schneller sein als i += 1 ? Sie tun genau das Gleiche ? Manchmal kann es einen Unterschied machen, ob man eine Konstante oder eine Variable hinzufügt, aber in diesem Fall fügt man in beiden Fällen die Konstante hinzu.

Und im Allgemeinen benötigen Anweisungen unabhängig von ihren Operanden eine feste, konstante Zeit. Die Addition von eins zu etwas dauert genauso lange wie die Addition von -2000 oder 1772051912. Das Gleiche gilt für die Multiplikation oder Division.

Aber wenn Sie Wert auf Leistung legen, müssen Sie verstehen. wie der gesamte Technologiestapel funktioniert, und nicht nur auf ein paar einfache Faustregeln wie "Ganzzahl ist schneller als Gleitkomma, und ++ ist schneller als += "(Abgesehen von allem anderen sind solche einfachen Faustregeln fast nie wahr, zumindest nicht in cada Fall)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X