He estado probando expresiones constantes que se evalúan en tiempo de compilación. Pero jugué con un ejemplo que parece increíblemente rápido cuando se ejecuta en tiempo de compilación.
#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;
}
Cuando ejecuto este código, tarda unos 7 segundos en ejecutarse. Hasta aquí todo bien. Pero cuando me cambio long int res = fib(45)
a const long int res = fib(45)
ella no lleva ni un segundo. A mi entender, se evalúa en tiempo de compilación.
Pero la compilación tarda unos 0.3 segundos
¿Cómo puede el compilador evaluar esto tan rápido, pero en tiempo de ejecución lleva mucho más tiempo? Estoy usando gcc 5.4.0.
fib
. La implementación de los números de Fibonacci que tiene arriba es muy lenta. Intente almacenar en caché los valores de la función en el código de tiempo de ejecución y será mucho más rápido.Respuestas:
El compilador almacena en caché valores más pequeños y no necesita volver a calcular tanto como la versión de tiempo de ejecución.
(El optimizador es muy bueno y genera mucho código, incluyendo trucos con casos especiales que son incomprensibles para mí; las ingenuas 2 ^ 45 recursiones tomarían horas).
Si también almacena valores anteriores:
La versión de tiempo de ejecución es mucho más rápida que el compilador.
fuente
fib
función dada no tiene efectos secundarios (no hace referencia a variables externas, la salida depende solo de las entradas), con un optimizador inteligente se puede hacer mucho.Puede encontrar interesante con 5.4 la función no se elimina por completo, necesita al menos 6.1 para eso.
No creo que haya ningún almacenamiento en caché. Estoy convencido de que el optimizador es lo suficientemente inteligente como para demostrar la relación entre
fib(n - 2)
yfib(n-1)
y evita la segunda llamada por completo. Esta es la salida GCC 5.4 (obtenida de godbolt) sinconstexpr
y -O2:Tengo que admitir que no entiendo la salida con -O3: el código generado es sorprendentemente complejo, con muchos accesos a la memoria y aritmética de puntero y es muy posible que haya algún almacenamiento en caché (memorización) con esa configuración.
fuente