Nous nous intéressons à l'estimation du temps de calcul des fonction factorial
et des fonctions power_by_int
que nous avons défini précédemment.
auto fn = estimate_function_time(factorial, 100); std::cout << "Computing fact(100)=" << fn .second << " in " << fn.first.count() << " ticks.\n"; auto pw = estimate_function_time(power_by_int<long double>, 1.0002, 1000000); std::cout << "Computing 1.02^1000000=" << pw.second << " in " << pw.first.count() << " ticks.\n";
Ceci nous retourne le temps mis pour calculer la fonction factorial
et pour la fonction power_by_int
.
Expérimenter.
Nous souvaitons indiquer au compilateur qu'il peut calculer au moment de la compilation les expressions si celles-ci sont constantes.
Pour ce faire nous ajoutons le mot-clé constexpr
devant la fonction ou l'expression dont la valeur peut-être exécuté au moment de la compilation.
Ainsi, nous pouvons indiquer que les deux fonctions factorial
et power_by_int
peuvent être calculer au moment de la compilation si les arguments sont des valeurs définies au moment de la compilation.
constexpr long double factorial(int n) { return n == 0 ? 1 : n * factorial(n - 1); } template<class numericalT> constexpr numericalT power_by_int(numericalT x, int y) { numericalT result = (numericalT)1.0; while (y-- > 0) result *= x; return result; }
Ceci autorise le compilateur a compilé l'expression au moment de la compilation.
Tester le code suivant:
auto fn = estimate_function_time(factorial, 100); std::cout << "Computing fact(100)=" << fn.second << " in " << fn.first.count() << " ticks.\n"; auto pw = estimate_function_time(power_by_int<long double>, 1.0002, 1000000); std::cout << "Computing 1.02^100000=" << pw.second << " in " << pw.first.count() << " ticks.\n";
A votre avis ? Est-ce que le compilateur à générer le code au moment de la compilation ?
En fait, nous pouvons aider naivement le compilateur en faisant bien apparaître le paramètre constant :
factorial_100 = []() { return factorial(100); }; fn = estimate_function_time(factorial_100); std::cout << "Computing fact(100)=" << fn.second << " in " << fn.first.count() << " ticks.\n"; power_10002_100000 = []() { return power_by_int<long double>, 1.0002, 100000); }; pw = estimate_function_time(power_10002_100000); std::cout << "Computing 1.02^1000000=" << pw.second << " in " << pw.first.count() << " ticks.\n";
Est-ce que cela améliore les résultats ? Tenter d'expliquer pourquoi ?
Il faut imposer que l'évaluation se fasse à la compilation. Pour ce faire, nous pouvons forcer à ce que l'expression soit évaluée en ajoutant l'attribue constexpr
à la variable résultat du calcul.
Ainsi le code suivant :
constexpr long double factorial(int n) { return n == 0 ? 1 : n * factorial(n - 1); } int main() { auto res = factorial(100); std::cout << res << "\n"; }
Indique que le compilateur peut effectué le calcul au moment de la compilation mais la plupart des compilateurs ne le font que partiellement.
Pour forcer, il est possible de déclarer la variable res
comme étant une variable stockant le résultat d'une expression constante :
int main() { auto res = factorial(100); std::cout << res << "\n"; }
Dans ce cas, le compilateur va lancer l'évaluation de factorial(100)
au moment de la compilation, en effet, il doit s'assurer que res
est une variable stockant le résultat d'une expression constante, le seul moyen de le vérifier est de calculer le résulat.
Ainsi on force bien l'évaluation au moment de l'exécution.
Modifier le code des lambda
expressions pour mettre en oeuvre ce mécanisme et estimer les temps de calculs.
Tester le code suivant avec un compilateur C++20:
template<double value, int power> struct constant_value { static constexpr long double constant() { constexpr auto result = power_by_int(value, power); return result; } };
et appeller cette fonction comme suit:
auto pw_c = estimate_function_time(precomputed_values<1.0002, 100000>::pow); std::cout << "Computing 1.02^1000000=" << pw_c.second << " in " << pw_c.first.count() << " ticks.\n"; }
Expliquer ce qui se passe ? Et pourquoi ce résultat.
Partie 2: Mesurer le temps passé par une fonction