This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
in204:tds:sujets:td3:part1 [2019/10/03 08:32] bmonsuez [Question n°2.1] |
in204:tds:sujets:td3:part1 [2022/11/18 10:49] (current) |
||
---|---|---|---|
Line 144: | Line 144: | ||
<hidden Correction> | <hidden Correction> | ||
+ | |||
Nous proposons plusieurs solutions au problème. Première approche, nous supprimons l'ensemble des valeurs dans le vecteur ''theVector'' en effectuant un appel à la fonction ''clear'' de l'object ''std::vector'' et nous ajoutons à la fin du vecteur, un par un les valeurs aléatoires que nous tirons en appelant la fonction ''push_back''. Suivez [[http://www.cplusplus.com/reference/vector/vector/|le lien]] pour plus d'informations relativement aux méthodes de la classe [[http://www.cplusplus.com/reference/vector/vector/|''std::vector'']]. | Nous proposons plusieurs solutions au problème. Première approche, nous supprimons l'ensemble des valeurs dans le vecteur ''theVector'' en effectuant un appel à la fonction ''clear'' de l'object ''std::vector'' et nous ajoutons à la fin du vecteur, un par un les valeurs aléatoires que nous tirons en appelant la fonction ''push_back''. Suivez [[http://www.cplusplus.com/reference/vector/vector/|le lien]] pour plus d'informations relativement aux méthodes de la classe [[http://www.cplusplus.com/reference/vector/vector/|''std::vector'']]. | ||
Line 294: | Line 295: | ||
</hidden> | </hidden> | ||
+ | |||
==== Question n°1.2 === | ==== Question n°1.2 === | ||
Line 305: | Line 307: | ||
<hidden Correction> | <hidden Correction> | ||
+ | |||
Votre fonction ressemblera à la fonction suivante : | Votre fonction ressemblera à la fonction suivante : | ||
Line 353: | Line 356: | ||
<hidden Correction> | <hidden Correction> | ||
+ | |||
Il s'agit d'un tri par insertion. Nous pouvons envisager d'implanter d'autre tri, comme un tri par bulles par exemple. | Il s'agit d'un tri par insertion. Nous pouvons envisager d'implanter d'autre tri, comme un tri par bulles par exemple. | ||
Line 422: | Line 426: | ||
} | } | ||
</code> | </code> | ||
+ | |||
</hidden> | </hidden> | ||
Line 429: | Line 434: | ||
<hidden Correction> | <hidden Correction> | ||
+ | |||
+ | |||
Il suffit d'écrire dans votre fnction ''main'' le code suivant : | Il suffit d'écrire dans votre fnction ''main'' le code suivant : | ||
Line 453: | Line 460: | ||
Nous avons dans le code précédent défini une portée débutant par ''{ using namespace monomorphic;''. Ceci indique que dans cette portée qui se termine avec le ''}'' correspondant nous importons l'ensemble des fonctions contenues dans l'espace de nom ''monomorphic''. Cette importation permet de ne pas avoir à écrire le préfix ''monomorphic::'' devant les fonctions ''populate_with_randoms'', ''print_vector'' et ''simple_sort''. | Nous avons dans le code précédent défini une portée débutant par ''{ using namespace monomorphic;''. Ceci indique que dans cette portée qui se termine avec le ''}'' correspondant nous importons l'ensemble des fonctions contenues dans l'espace de nom ''monomorphic''. Cette importation permet de ne pas avoir à écrire le préfix ''monomorphic::'' devant les fonctions ''populate_with_randoms'', ''print_vector'' et ''simple_sort''. | ||
+ | |||
</hidden> | </hidden> | ||
Line 486: | Line 494: | ||
<hidden Correction> | <hidden Correction> | ||
+ | |||
+ | |||
Pour une fonction (resp. une classe) qui est définie par un patron de fonction (resp. de classe), la génération du code s'effectuant au moment de l'appel de la fonction (resp. de la création d'un objet). Pour que le compilateur soit en mesure d'effectuer cette génération de code, il est nécessaire que le code soit disponible, cela signifie que le code soit présent dans le fichier qui sera inclut. | Pour une fonction (resp. une classe) qui est définie par un patron de fonction (resp. de classe), la génération du code s'effectuant au moment de l'appel de la fonction (resp. de la création d'un objet). Pour que le compilateur soit en mesure d'effectuer cette génération de code, il est nécessaire que le code soit disponible, cela signifie que le code soit présent dans le fichier qui sera inclut. | ||
Line 558: | Line 568: | ||
</hidden> | </hidden> | ||
+ | |||
==== Question n°2.2 ==== | ==== Question n°2.2 ==== | ||
Proposer une réécriture des fonctions ''populate_with_randoms'', ''print_vector'' et ''simple_sort'' pour qu’elles puissent fonctionner avec n’importe quel autre type comme des ''double'', des ''float'', des ''short'', des ''unsigned''. | Proposer une réécriture des fonctions ''populate_with_randoms'', ''print_vector'' et ''simple_sort'' pour qu’elles puissent fonctionner avec n’importe quel autre type comme des ''double'', des ''float'', des ''short'', des ''unsigned''. | ||
+ | |||
+ | <hidden Correction> | ||
+ | |||
+ | |||
+ | Nous nous restreignons pour l'instant à des types dénotant des valeurs numériques et supportant nativement une conversion soit implicite soit explicite d'un type entier supporté par le générateur de nombre aléatoire et le type des valeurs stockées dans le tableau dynamique. | ||
+ | |||
+ | Lorsque nous nous intéressons au prototype de la fonction ''populate_with_randoms'' monomorphes : | ||
+ | |||
+ | <code cpp> | ||
+ | void populate_with_randoms( | ||
+ | std::vector<int>& theVector, | ||
+ | int theNumberOfValues, int theMinValue, int theMaxValue); | ||
+ | </code> | ||
+ | |||
+ | Il serait tentant de remplacer toutes les instances de ''int'' par un paramètre de type ''T''.\\ | ||
+ | Ceci donnerait la signature suivante : | ||
+ | |||
+ | <code cpp> | ||
+ | template<typename T> | ||
+ | void populate_with_randoms( | ||
+ | std::vector<T>& theVector, | ||
+ | T theNumberOfValues, T theMinValue, T theMaxValue) | ||
+ | { | ||
+ | std::random_device rd; | ||
+ | std::minstd_rand gen(rd()); | ||
+ | std::uniform_int_distribution<T> distribution(theMinValue, theMaxValue); | ||
+ | theVector.clear(); | ||
+ | for(; | ||
+ | theNumberOfValues > 0; | ||
+ | theNumberOfValues --) | ||
+ | { | ||
+ | theVector.push_back( | ||
+ | (T)distribution(gen)); | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | qui en fait serait totalement inadaptée. \\ | ||
+ | En effet, pour le type ''T=double'', nous nous retrouverons avec la signature : | ||
+ | <code cpp> | ||
+ | void populate_with_randoms<double>( | ||
+ | std::vector<double>& theVector, | ||
+ | double theNumberOfValues, double theMinValue, double theMaxValue) | ||
+ | { | ||
+ | std::random_device rd; | ||
+ | std::minstd_rand gen(rd()); | ||
+ | std::uniform_int_distribution<double> | ||
+ | distribution(theMinValue, theMaxValue); | ||
+ | // !!!! l'instantiation uniform_int_distribution<double> | ||
+ | // n'est pas supportée | ||
+ | theVector.clear(); | ||
+ | for(; | ||
+ | theNumberOfValues > 0; | ||
+ | theNumberOfValues --) | ||
+ | // Fonctionne mais theNumberOfValues n'est pas | ||
+ | // a priori une valeur flottante mais un entier ! | ||
+ | { | ||
+ | theVector.push_back( | ||
+ | (double)distribution(gen)); | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | Il est donc nécessaire de bien séparer les différents types des paramètres : | ||
+ | |||
+ | * ''std::vector<int>& theVector'' => nous pouvons étendre le support de la fonction à tous les types ''T'' génériques correspondant à des types numériques. | ||
+ | * int theNumberOfValues => cet élément reste un nombre entier, éventuellement nous pouvons y substituer le type ''size_t''. | ||
+ | * int theMinValue, int theMaxValue => le support de la fonction peut être étendu à tous les types supportés par la classe [[https://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution|std::uniform_int_distribution]]. | ||
+ | |||
+ | Dans ce cas, nous pouvons redéfinir le patron de la fonction comme suit : | ||
+ | |||
+ | <code cpp> | ||
+ | namespace generic | ||
+ | { | ||
+ | template<typename T, typename genType> | ||
+ | void populate_with_randoms( | ||
+ | std::vector<T>& theVector, | ||
+ | size_t theNumberOfValues, | ||
+ | genType theMinValue, genType theMaxValue) | ||
+ | { | ||
+ | std::random_device rd; | ||
+ | std::minstd_rand gen(rd()); | ||
+ | std::uniform_int_distribution<genType> distribution(theMinValue, theMaxValue); | ||
+ | theVector.clear(); | ||
+ | for(; | ||
+ | theNumberOfValues > 0; | ||
+ | theNumberOfValues --) | ||
+ | { | ||
+ | theVector.push_back( | ||
+ | (genType)distribution(gen)); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | Pour les fonctions ''print_vector'' et ''simple_sort'', la généralisation est simple, puisqu'il n'y a qu'un paramètre à généraliser qui est le type des valeurs stockées dans le tableau dynamique. | ||
+ | |||
+ | <code cpp> | ||
+ | namespace generic | ||
+ | { | ||
+ | ... | ||
+ | |||
+ | template<typename T> | ||
+ | void print_vector(const std::vector<T>& anArray) | ||
+ | { | ||
+ | int length = anArray.size(); | ||
+ | std::cout << "["; | ||
+ | for(int index = 0; index < length - 1; index ++) | ||
+ | std::cout << anArray[index] << ", "; | ||
+ | std::cout << anArray[length - 1] << "]" << std::endl; | ||
+ | } | ||
+ | template<typename T> | ||
+ | void simple_sort(std::vector<T>& theValues) | ||
+ | { | ||
+ | int length = theValues.size(); | ||
+ | for(int i = 0; i < length-1; i ++) | ||
+ | { | ||
+ | for(int j= i+1; j < length; j++) | ||
+ | { | ||
+ | if(theValues[i] > theValues[j]) | ||
+ | std::swap(theValues[i], theValues[j]); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | </hidden> | ||
==== Question n°2.3 === | ==== Question n°2.3 === | ||
Line 567: | Line 706: | ||
<hidden Correction> | <hidden Correction> | ||
+ | |||
Vous créez une fonction ''main'' pour appeller les fonctions précédentes pour différents types. Dans l'exemple suivant qui est proposé, nous testons les fonctions génériques pour les types ''int'', ''float'', ''char''. Vous pouvez tester avec d'autres types supportant la conversion d'une valeur numérique vers le type ''T''. | Vous créez une fonction ''main'' pour appeller les fonctions précédentes pour différents types. Dans l'exemple suivant qui est proposé, nous testons les fonctions génériques pour les types ''int'', ''float'', ''char''. Vous pouvez tester avec d'autres types supportant la conversion d'une valeur numérique vers le type ''T''. | ||
Line 603: | Line 743: | ||
Pour les types ''int'' et ''float'', le comportement est équivalent à celui des fonctions monomorphiques puisque notre implantation du générateur de nombres aléatoires génère des entiers entre les valeurs minimales et maximales. Lors de l'affichage des valeurs dans le vecteur, que le type soit ''int'' ou ''float'', les valeurs sont des valeurs entières. Cependant dans le dernier cas, nous manipulons des caractères et plus exactement le code ASCII des caractères. Nous générons les codes aléatoirements entre 'A' et 'Z', quand la fonction ''print_vector'' affiche les valeurs, elle affiche le caractère correspondant au code ASCII situé entre la valeur représentant 'A' et la valeur représentant 'Z'. En conséquence de quoi, elle affiche un caractère supérieur ou égal à 'A' et inférieur ou égal à 'Z'. | Pour les types ''int'' et ''float'', le comportement est équivalent à celui des fonctions monomorphiques puisque notre implantation du générateur de nombres aléatoires génère des entiers entre les valeurs minimales et maximales. Lors de l'affichage des valeurs dans le vecteur, que le type soit ''int'' ou ''float'', les valeurs sont des valeurs entières. Cependant dans le dernier cas, nous manipulons des caractères et plus exactement le code ASCII des caractères. Nous générons les codes aléatoirements entre 'A' et 'Z', quand la fonction ''print_vector'' affiche les valeurs, elle affiche le caractère correspondant au code ASCII situé entre la valeur représentant 'A' et la valeur représentant 'Z'. En conséquence de quoi, elle affiche un caractère supérieur ou égal à 'A' et inférieur ou égal à 'Z'. | ||
+ | |||
</hidden> | </hidden> | ||