User Tools

Site Tools


in204:tds:sujets:td9:part1

This is an old revision of the document!


Partie 1 : Manipuler un ensemble d'arguments

Question 1

Ecrire une fonction print qui prend un nombre libre d'entiers en paramètres et qui affiche ces entiers sur la console.

Pour ce faire, nous vous conseillons d'autiliser la classe std::initializer_list<T> comme argument de la fonction.

Un std::initializer_list<T> permet d'accéder à la une liste de valeurs de type T qui est écrit sous la forme suivante :

std::initializer_list<int> list_of_values = {1, 3, 4, 2 };

Cette liste de valeur n'est pas modifiable. Il est seulement possible de la lire en lecture comme un containeur classique. Les fonctions begin(), end() ainsi que size() permettent d'accéder aux valeurs stockées dans la liste.

Correction

Correction

void print(std::initializer_list<int> arguments)
{
    auto it = arguments.begin(),
        end_it = arguments.end();
    if (it != end_it)
    {
        std::cout << *it;
        while (++it != end_it)
            std::cout << ", " << *it;        
    }
}

Question 2

Généraliser cette fonction à d'autres types que les types entiers.

Cette fois-ci, nous attaquons les choses un peu plus complexes. En effet, pour cela, vous allez utiliser les packs de paramètres des fonctions et des classes templatées.

Quand nous écrivons :

  • template<class …Args> f(Args… arguments), cela signifie que la fonction prend comme arguments un ensemble d'arguments qui ont des types différents. La variable arguments fait référence à l'ensemble des valeurs ayant chacun un type différent, c'est pour cela que l'on parle de pack de paramètres. Attention, il n'est pas possible d'accéder aux données individuelles présentes dans le pack de paramètres.
  • l'opérateur sizeof…(Args) permet d'obtenir le nombres d'arguments passés à la fonction ou spécifié comme paramètres de la classe.
  • En fait, les packs de paramètres servent à être passés directement à une fonction. Ainsi nous pouvons écrire le code suivant :
void number_of_args() { std::cout << "no arguments"; }
template<classT> void number_of_args(T) { std::cout << "one argument"; }
template<classT1, class T2> void number_of_args(T1, T2) { std::cout << "two arguments"; }
 
template<class ...Args>
void func(Args... arguments)
{
    return number_of_args(arguments...);
}

va appeller en fonction du nombre d'arguments l'une des fonctions number_of_args.

Nous pouvons désormais imaginer une approche récursive pour compter le nombre d'arguments en implantant le code suivant :

template<class ...Args>
int number_of_args(T first_argument, Args... arguments)
{
    return 0;
}
template<class T, class ...Args>
int number_of_args(T first_argument, Args... arguments)
{
    return 1 + number_of_args(arguments);
}

L'appel de la fonction number_of_args qui suit :

    std::cout << number_of_args(1, "e", 2.0, 'c') << "\n";

retournera 4.

Question 2.1

Expliquer comment le code a été exécuté ?

Question 2.2

En vous inspirant du code précédant, proposer une fonction print qui prend un nombre variable de paramètres qui peuvent avoir des types différents et qui imprime cette liste de paramètres sur la console.

Correction

Correction

template<class T> void print(T first_argument) {

  std::cout << first_argument;

}

template<class T, class …Args> void print(T first_argument, Args… arguments) {

  std::cout << first_argument;
  if (sizeof...(Args) > 0)
      std::cout << ", ";
  print(arguments...);

}

Partie 2 :Mesuré le temps passé par une fonction

TD9

Références

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

int factorial(int n)
{
    return n <= 1 ? 1 : (n * factorial(n - 1));
}

La fonction aura le squelette suivant:

int estimate_time(int n)
{
    // Code pour lancer le chronomètre
    int result = factorial(n);
    // Code pour calculer le temps écoulé et affiché celui-ci.
    return result;
}

Question n°2

Transformer la fonction précédente

estimate_time

pour qu'elle prenne en argument une fonction arbitraire à un argument et un résultat.

Il faudra penser à utiliser un modèle (template) de fonctions.

Correction

Correction

Il suffit de modifier la fonction antérieure comme un fonction qui prend deux paramètres de types:

  1. le type correspondant à la fonction,
  2. le type correspondant au paramètre de la fonction.

Et le tour est joué. Ceci donne le code suivant :

template<class Function, class T>
std::pair<std::chrono::high_resolution_clock::duration, long double> 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);
}

Question n°3

Nous souhaitons désormais pouvoir prendre une fonction pouvant prendre plusieurs arguments comme la fonction puissance.

template<class T1, T2> 
T1 power(T2 x, int y)
{
   T1 result = (T1)1.0
   while(y-- > 0)
       result  = result * (T1)x;
   return result;
}

Modifier le code de la fonction pour pouvoir prendre une telle fonction comme paramètre.

Estimer le temps nécesaire pour calculer par exemple : 1.02 ^ 10000000.

Question n°5

Créer une fonction nouvelle qui va appeller la fonction

estimate_time

pour calculer

x

fois le temps et retourné le temps moyen pour effectuer un “run” de la fonction.

Exécuter cette fonction pour les fonctions

power

et

factorial

précédemment définie.

Question n°4

Que faut-il faire ajouter pour dire au compilateur que la fonction

factorial

ou que la fonction

power

peut-être exécutée au moment de l'exécution ?

Effectuer la modification.

Calculer le temps pris désormais par ces fonctions.

in204/tds/sujets/td9/part1.1636209850.txt.gz · Last modified: 2021/11/06 14:44 by bmonsuez