Optimieren C- und C++-Compiler Vergleiche mit Funktionsaufrufen?

Lesezeit: 6 Minuten

Benutzer-Avatar
Wander Nauta

Optimieren C- und C++-Compiler im Allgemeinen Vergleiche mit Funktionen?

Zum Beispiel, diese Seite schlägt vor, dass die size Funktion auf std::lists in C++ kann in einigen Standardbibliotheksimplementierungen eine lineare Komplexität O(N) haben (was für eine verkettete Liste sinnvoll ist).

Aber in diesem Fall, wenn myList ist eine riesige Liste, was würde so etwas bewirken?

    if (myList.size() < 5) return 1;
    else return 2;

Würde die Funktion size() alle N Listenmitglieder finden und zählen, oder wäre sie für einen Kurzschluss optimiert, nachdem 5 Mitglieder gefunden wurden?

  • Wenn ja size() Der lange Weg herauszufinden, dass das Stoppen nach 5 eine gute Idee ist, ist für einen Compiler unglaublich schwierig.

    – Flexo

    11. Mai 2012 um 11:20 Uhr


  • Es gibt möglicherweise Spielraum dafür, wenn es inline ist size aber ich denke, es ist ein Weitschuss zu erkennen, dass es aus einer Schleife ausbrechen kann, die einen Zähler erhöht.

    – Rup

    11. Mai 2012 um 11:21 Uhr

  • Ich würde mir keine Sorgen machen. Während der C++03-Standard keine O(1)-Komplexität für erforderte size()das tat es empfehlen es, und es ist einfach zu implementieren. Ich wäre überrascht, wenn Ihre Implementierung die Anzahl der Elemente im Container nicht verfolgen würde (Sie können dies leicht überprüfen, indem Sie die <list> Header.

    – David Rodríguez – Dribeas

    11. Mai 2012 um 11:33 Uhr

  • @WanderNauta: Das Problem damit, eine allgemeine Frage stellen zu wollen und eine bestimmte Frage zu stellen, ist, dass Sie Antworten auf die bestimmte Frage erhalten. Wenn die Frage allgemein ist, lautet die Antwort, dass der Compiler dies in den meisten Fällen nicht kann. Der Fall a size() auf einer Liste ist ein Sonderfall in dem Sinne, dass der Compiler als Vorlage die Definition der Funktion hat und damit gibt es etwas entfernte Chance, dass es es herausfinden könnte. Im Allgemeinen hat der Compiler keinen Zugriff auf die Definition der Funktionen und die Optimierungsmöglichkeiten sind viel schwieriger.

    – David Rodríguez – Dribeas

    11. Mai 2012 um 11:43 Uhr

  • Ganz im Gegenteil, selbst mit Inlining gibt es nur sehr wenige Chancen, ohne es, vergessen Sie es, die Funktion muss vollständig ausgeführt werden, bevor der Vergleich durchgeführt werden kann

    – David Rodríguez – Dribeas

    11. Mai 2012 um 11:52 Uhr

Benutzer-Avatar
Jon

Theoretisch besteht die Möglichkeit ggf size() war inline, aber um die Optimierung durchzuführen, müsste der Compiler dies tun

  1. Erkennen Sie, dass Sie speziell eine „kleiner als“-Bedingung testen
  2. Beweisen Sie, dass die Schleife (angenommen, eine existiert für die Zwecke dieser Diskussion) zu einer monoton steigenden Variablen führt
  3. Beweisen Sie, dass es keine beobachtbaren Nebenwirkungen des Schleifenkörpers gibt

Das ist meiner Meinung nach eine Menge Dinge, auf die man sich verlassen kann, und es enthält Funktionen, die auch in anderen Zusammenhängen nicht “offensichtlich nützlich” sind. Denken Sie daran, dass Compiler-Anbieter nur begrenzte Ressourcen haben, also muss es wirklich gute Gründe dafür geben, diese Voraussetzungen zu implementieren und den Compiler alle Teile zusammenbringen zu lassen, um diesen Fall zu optimieren.

Auch wenn dies für jemanden ein Leistungsproblem ist Das Problem kann leicht im Code gelöst werden, Ich glaube nicht, dass es eine solche Rechtfertigung geben würde. Also nein, im Allgemeinen sollten Sie nicht erwarten, dass solche Fälle optimiert werden.

  • Ich bin verwirrt. Warum müsste der Wert monoton steigen?

    – Wander Nauta

    11. Mai 2012 um 11:26 Uhr

  • @WanderNauta: Denn wenn dies nicht der Fall wäre, bliebe keine andere Wahl, als alle Iterationen durchzuführen, um festzustellen, ob der Endwert kleiner als 5 ist.

    – Oliver Charlesworth

    11. Mai 2012 um 11:28 Uhr


  • Eigentlich ist es nicht so schlimm. Das Zählen der Listenlänge ist nicht so komplex. Und ich weiß, dass moderne Optimierer sogar UB beim Überlauf von vorzeichenbehafteten Ganzzahlen ausnutzen, um festzustellen, ob eine Reihe von Inkrementen zu einer monoton ansteigenden Variablen führt. (unsigned tut es seitdem nicht UINT_MAX+1 < UINT_MAX).

    – MSalter

    12. Mai 2012 um 12:56 Uhr

Eigentlich in C++11, std::list ist optimiert u size() wird in konstanter Zeit zurückgegeben.

Für C++03, size() arbeitet tatsächlich in linearer Zeit, da es jedes Mal die Elemente zählen muss.

Würde die Funktion size() alle N Listenmitglieder finden und zählen, oder wäre sie für einen Kurzschluss optimiert, nachdem 5 Mitglieder gefunden wurden?

Ich habe diese Art der Optimierung in der Praxis noch nie gesehen. Obwohl es sicherlich legal ist, bezweifle ich, dass es einen Compiler gibt, der so etwas tatsächlich implementiert.

  • Nur als Randbemerkung, ähnlicher Code in einer funktionalen Programmiersprache wie Haskell wird nur bis zur erforderlichen Tiefe erweitert.

    – Jaywalker

    11. Mai 2012 um 11:38 Uhr

  • @Jaywalker: Ich bin mir nicht so sicher wie du. Sie müssen eine erstellen longer-than Methode für diese mich denkt.

    – Matthias M.

    11. Mai 2012 um 11:49 Uhr

  • Ich halte mich da raus, bis ich das Etikett auf SO gesehen habe, wusste ich nicht, was Haskell ist. Ich habe StandardML im College gemacht.

    – Luchian Grigore

    11. Mai 2012 um 11:50 Uhr

  • In C++ könnte die Optimierung mit abscheulicher Operatorüberladung für die erfolgen < Operator…..

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    11. Mai 2012 um 13:23 Uhr

  • @Jaywalker Ab sofort length xs < k wird die gesamte Liste in GHC durchlaufen, und ich kenne keine Implementierung, die sie verkürzt. Sie würden Abkürzungen mit bekommen genericLength xs < k und einen geeigneten Lazy-Number-Typ. Oder mit einer Rewrite-Regel forall k xs. length xs < k = if k < 1 then False else null (drop (k-1) xs), aber das wäre Ihre eigene Sache, nicht die des Compilers. Und es würde das Verhalten für ändern length (1:2:undefined) < 2 Aus diesem Grund kann der Compiler sie beispielsweise nicht bereitstellen.

    – Daniel Fischer

    11. Mai 2012 um 14:04 Uhr

Die Funktion myList.size() selbst kann nicht für den Zweck kompiliert werden, für den Sie sie verwenden, daher bestimmt sie die gesamte Größe. Um die von Ihnen vorgeschlagene Optimierung zu erhalten, benötigen Sie anstelle der allgemeinen eine dedizierte Prädikatfunktion size()etwas wie bool sizeLessThan(int);.

  • Aber theoretisch ist dies eine Optimierung, die der Compiler beobachten könnte. Die Frage ist, kommt so etwas in der Praxis vor?

    – Oliver Charlesworth

    11. Mai 2012 um 11:23 Uhr

  • Wenn der Compiler beweisen kann, dass der Rest keine Rolle spielt, hat er das Recht, sich nicht darum zu kümmern, solange das beobachtbare Verhalten korrekt ist. Es ist theoretisch möglich, dass ein Compiler dies beweist, nur ein wenig knifflig in der Praxis.

    – Flexo

    11. Mai 2012 um 11:23 Uhr


  • Sicher, es ist möglich, aber um dies zu bekommen, wäre etwas Nicht-Allgemeines erforderlich. Sie müssen damit rechnen, dass sich Code für solche Dinge (im allgemeinen Fall) entweder in einer Bibliothek oder zumindest in einem anderen Objekt befindet und daher auf generische Weise verknüpft ist (was die Wahrscheinlichkeit solcher spezialisierter Optimierungen eliminiert).

    – mah

    11. Mai 2012 um 11:25 Uhr

NEIN Sie fragen, ob der Compiler bewirken kann, dass sich eine Funktion je nach Verwendung ihrer Ergebnisse unterschiedlich verhält. Dies könnte möglicherweise nur für Inline-Funktionen durchgeführt werden, bei denen der Aufrufer und die Funktion gleichzeitig zusammen kompiliert werden. Es scheint eine ziemliche Strecke für alles darüber hinaus zu sein.

1205590cookie-checkOptimieren C- und C++-Compiler Vergleiche mit Funktionsaufrufen?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy