User Tools

Site Tools


in204:tds:sujets:td12_2023:part2

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

in204:tds:sujets:td12_2023:part2 [2023/12/04 11:23] (current)
bmonsuez created
Line 1: Line 1:
 +====== Partie 2 : Mesurer le temps passé par une fonction ======
 +
 +[[in204:​tds:​sujets:​td12_2023|TD12]]
 +
 +===== Références=====
 +
 +[[https://​en.cppreference.com/​w/​cpp/​chrono/​high_resolution_clock|std::​chrono::​high_resolution_clock]]
 +
 +[[https://​en.cppreference.com/​w/​cpp/​utility/​pair/​make_pair|str::​make_pair(...)]]
 +
 +[[https://​en.cppreference.com/​w/​cpp/​utility/​pair/​pair|str::​pair<​T1,​ T2>]]
 +
 +====== Partie n°1 ======
 +
 +Nous souhaitons mesurer le temps de calcul d'une fonction. Pour ce faire, nous souhaitons créer une fonction :
 +- qui va prendre en argument la fonction que nous souhaitons exécuter,
 +- les arguments que nous devons passer à cette fonction,
 +- qui va lancer un chronomètre,​
 +- qui va lancer la fonction
 +- qui va récupérer le résultat de la fonction,
 +- qui va estimer le temps passé par le temps de la fonction,
 +- qui va retourner à la fois le  résultat de la fonction mais aussi le temps passé par la fonction.
 +
 +===== Question n°1 =====
 +
 +Pour simplifier la conception, écrivez dans un premier la fonction qui appelle la fonction factorielle qui suit:
 +et qui va exécuter cette fonction
 +
 +<code cpp>
 +int factorial(int n)
 +{
 +    return n == 0 ? 1 : (n * factorial(n - 1));
 +}
 +</​code>​
 +
 +La fonction aura le squelette suivant:
 +<code cpp>
 +std::​pair<​std::​chrono::​high_resolution_clock::​duration,​ int> estimate_factorial_time(int n)
 +{
 +    // Code pour lancer le chronomètre
 +    int result = factorial(n);​
 +    // Code pour calculer le temps écoulé
 +    // Retourner la paire contenant le résultat et le temps passé.
 +}
 +</​code>​
 +
 +<hidden Correction>​
 +
 +Ceci est assez simple à réaliser en utilisant les fonctions ''​std::​chrono::​high_resolution_clock::​now()''​ et ''​std::​make_pair()''​.
 +
 +<code cpp>
 +std::​pair<​std::​chrono::​high_resolution_clock::​duration,​ long double> estimate_factorial_time(int n)
 +{
 +    auto starting_time = std::​chrono::​high_resolution_clock::​now();​
 +    auto result = factorial(n);​
 +    auto elasped_time = std::​chrono::​high_resolution_clock::​now() - starting_time;​
 +    return std::​make_pair(elasped_time,​ result);
 +}
 +</​code>​
 +
 +</​hidden>​
 +
 +
 +===== Question n°2 =====
 +
 +Transformer la fonction précédente <​code>​estimate_time</​code>​ pour qu'​elle prenne en argument une fonction arbitraire qui prend un argument et retourne un résultat qui ne sera pas obligatoirement un résultat de type ''​long double''​. ​
 +
 +Il faudra penser à utiliser un modèle (template) de fonctions.
 +
 +<hidden Correction>​
 +
 +Il suffit de modifier la fonction antérieure comme un fonction qui prend deux paramètres de types:
 +  - le type correspondant à la fonction,
 +  - le type correspondant au paramètre de la fonction.
 +
 +Et le tour est joué. Ceci donne le code suivant :
 +
 +<code cpp>
 +template<​class Function, class T>
 +auto estimate_function_time(Function function, T argument)
 +{
 + auto starting_time = std::​chrono::​high_resolution_clock::​now();​
 + auto result = function(argument);​
 + auto elasped_time = std::​chrono::​high_resolution_clock::​now() - starting_time;​
 + return std::​make_pair(elasped_time,​ result);
 +}
 +</​code>​
 +
 +</​hidden>​
 +
 +
 +===== Question n°3 =====
 +
 +Nous souhaitons désormais pouvoir prendre une fonction pouvant prendre plusieurs arguments comme la fonction puissance.
 +
 +<code cpp>
 +template<​class numericalT>​
 +numericalT power_by_int(numericalT x, int y)
 +{
 +    numericalT result = (numericalT)1.0;​
 +    while (y-- > 0)
 +      result *= x;
 +    return result;
 +}
 +</​code>​
 +
 +Modifier le code de la fonction pour pouvoir prendre une telle fonction comme paramètre.
 +
 +__**Remarque**__:​ il faut penser à utiliser les **packs de paramètres** que nous avons vu dans la première partie du TD.
 +
 +<hidden Correction>​
 +Dans le cas présent, comme nous avons aucun, un ou plusieurs paramètres,​ chacun des paramètres pouvant avoir un type différent. Dans ce cas, nous pouvons remplacer le paramêtre ''​T''​ de la fonction ''​estimate_function_time''​ précédenter par un argument correspondant à un pack de paramètres ''​...Args''​. Et c'est tout !
 +
 +template<​class Function, class ... Args>
 +auto estimate_function_time(Function function, Args... arguments)
 +{
 + auto starting_time = std::​chrono::​high_resolution_clock::​now();​
 + auto result = function(arguments...);​
 + auto elasped_time = std::​chrono::​high_resolution_clock::​now() - starting_time;​
 + return std::​make_pair(elasped_time,​ result);
 +}
 +
 +</​hidden>​
 +
 +Estimer le temps nécesaire pour calculer par exemple : 1.0002 ^ 10000000.
 +
 +<hidden Correction>​
 +
 +Le code suivant va permettre d'​estimer le temps passé à calculer le résultat :
 +
 +<code cpp>
 +    auto pw = estimate_function_time(power_by_int<​long double>, 1.0002, 1000000);
 +    std::cout << "​Computing 1.02^1000000="​ << pw.second << " in " << pw_10000000.first.count() << " ticks.\n";​
 +</​code>​
 +
 +</​hidden>​
 +
 +
 +==== Question n°5 ====
 +
 +Créer une fonction nouvelle qui va appeller la fonction ​ ''​estimate_function_time''​ pour calculer ''​x''​ fois le temps nécessaire pour calculer la fonction et qui retourn le temps moyen pour effectuer un "​run"​ de la fonction.
 +
 +
 +Cette fonction aura l'​entête suivante :
 +
 +<code cpp>
 +template<​class Function, class ... Args>
 +long long mean_function_time(int number_of_runs,​ Function function, Args... arguments)
 +{
 +...
 +}
 +</​code>​
 +
 +<hidden Correction>​
 +
 +Il suffit de lancer ''​number_of_runs''​ fois un appel à ''​estimate_function_time''​ pour la fonction et les arguments. Ceci donne le code suivant :
 +
 +<code cpp>
 +template<​class Function, class ... Args>
 +long long mean_function_time(int number_of_runs,​ Function function, Args... arguments)
 +{
 + long long duration = 0L;
 + int remaining_runs = number_of_runs;​
 + while (remaining_runs-- > 0)
 + duration += estimate_function_time(function,​ arguments...).first.count();​
 + return duration / (long long)number_of_runs;​
 +}
 +</​code>​
 +
 +</​hidden>​
 +
 +====== Navigation ======
 +
 +Partie 1: [[.part1|Manipuler un nombre variable de paramètres]]\\
 +Partie 3: [[.part3|Exécution à la compilation]]
  
in204/tds/sujets/td12_2023/part2.txt · Last modified: 2023/12/04 11:23 by bmonsuez