Ich habe const-Ausdrücke ausprobiert, die zur Kompilierungszeit ausgewertet werden. Aber ich habe mit einem Beispiel gespielt, das unglaublich schnell erscheint, wenn es zur Kompilierungszeit ausgeführt wird.
#include<iostream>
constexpr long int fib(int n) {
return (n <= 1)? n : fib(n-1) + fib(n-2);
}
int main () {
long int res = fib(45);
std::cout << res;
return 0;
}
Wenn ich diesen Code ausführe, dauert die Ausführung ca. 7 Sekunden. So weit, ist es gut. Aber wenn ich dazu wechsle long int res = fib(45)
, const long int res = fib(45)
dauert es nicht einmal eine Sekunde. Nach meinem Verständnis wird es zur Kompilierungszeit ausgewertet.
Die Kompilierung dauert jedoch ca. 0,3 Sekunden
Wie kann der Compiler dies so schnell auswerten, aber zur Laufzeit dauert es so viel länger? Ich benutze gcc 5.4.0.
fib
. Die Implementierung der Fibonacci-Zahlen, die Sie oben haben, ist vorab ziemlich langsam. Versuchen Sie, die Funktionswerte im Laufzeitcode zwischenzuspeichern, und dies wird viel schneller.Antworten:
Der Compiler speichert kleinere Werte zwischen und muss nicht so viel neu berechnen wie die Laufzeitversion.
(Der Optimierer ist sehr gut und generiert viel Code, einschließlich Tricks mit Sonderfällen, die für mich unverständlich sind. Die naiven 2 ^ 45-Rekursionen würden Stunden dauern.)
Wenn Sie auch vorherige Werte speichern:
Die Laufzeitversion ist viel schneller als der Compiler.
quelle
fib
Funktion hat keine Nebenwirkungen (verweist auf keine externen Variablen, die Ausgabe hängt nur von den Eingaben ab). Mit einem cleveren Optimierer kann viel getan werden.Vielleicht finden Sie mit 5.4 interessant, dass die Funktion nicht vollständig eliminiert ist, dafür benötigen Sie mindestens 6.1.
Ich glaube nicht, dass Caching stattfindet. Ich bin überzeugt, dass der Optimierer klug genug ist, um die Beziehung zwischen
fib(n - 2)
und zu beweisenfib(n-1)
und den zweiten Aufruf vollständig zu vermeiden. Dies ist die GCC 5.4-Ausgabe (von Godbolt erhalten) mit noconstexpr
und -O2:Ich muss zugeben, dass ich die Ausgabe mit -O3 nicht verstehe - der generierte Code ist überraschend komplex, mit vielen Speicherzugriffen und Zeigerarithmetik, und es ist durchaus möglich, dass mit diesen Einstellungen etwas Caching (Memoization) durchgeführt wird.
quelle