User Tools

Site Tools


in204:tds:sujets:td9:part3

Differences

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

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
in204:tds:sujets:td9:part3 [2021/11/08 12:24]
bmonsuez [Question 2 :]
in204:tds:sujets:td9:part3 [2022/11/18 10:49] (current)
Line 1: Line 1:
-====== ​Partie 3 : Exécution ​à la compilation ​======+====== Exécution ​asynchrone ​======
  
 [[in204:​tds:​sujets:​td9|TD9]] [[in204:​tds:​sujets:​td9|TD9]]
Line 5: Line 5:
 ===== Références===== ===== Références=====
  
 +[[http://​en.cppreference.com/​w/​cpp/​thread/​async|std::​async]] [[http://​en.cppreference.com/​w/​cpp/​thread/​future|std::​future]]
  
-===== Question ​1 : ===== +===== Question ​n°1 =====
- +
-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.+
  
 +Nous considérons la fonction suivante qui calcule les décimales de « e ».
 <code cpp> <code cpp>
-    auto fn =  estimate_function_time(factorial,​ 100); +std::string computeE(int numberOfDigits)
-    ​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";​ +
-</​code>​ +
- +
-Ceci nous retourne le temps mis pour calculer la fonction ''​factorial''​ et pour la fonction ''​power_by_int''​. +
- +
-Expérimenter. +
- +
-===== Question 2 : ===== +
- +
- +
-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. +
- +
-<code cpp> +
-constexpr long double factorial(int n)+
 { {
- return n == 0 : n * factorial(- 1); + int sizeOfTable ​numberOfDigits + 9; 
-}+ int* table (int*)_alloca(sizeOfTable * sizeof(numberOfDigits));​ 
 + table[0] = 0; 
 + table[1] = 2; 
 + for (int i = sizeOfTable ​- 1; i > 0; i--
 + table[i] = 1
 + }
  
-template<​class numericalT>​ + std::​ostringstream output; 
-constexpr numericalT power_by_int(numericalT x, int y+ int x = 0; 
-+ table[1] = 2; 
- numericalT result = (numericalT)1.0; + for (; sizeOfTable > 9; sizeOfTable -- )  
- while (y-- > 0+
- result *= x; + for (int i = sizeOfTable - 1; i > 0; i--)  
- return ​result;+
 + table[i] ​= x % i; 
 + x = 10 * table[i - 1] + x / i; 
 +
 + output << x; 
 + } 
 + return ​output.str();
 } }
 </​code>​ </​code>​
  
-Ceci autorise le compilateur a compilé l'​expression au moment de la compilation.+Implanter ​la fonction et vérifier que celle-ci fonctionne correctement.
  
- +<hidden Correction>​
-===== Question 1 : ===== +
- +
-Tester le code suivant:+
  
 <code cpp> <code cpp>
 +#​include<​sstream>​
 +#​include<​iostream>​
  
-auto fn = estimate_function_time(factorial, 100); +std::string computeE(int numberOfDigits) 
-std::cout << "​Computing fact(100)=" << fn.second << " in " << fn.first.count() << " ticks.\n"​;+
 + int sizeOfTable = numberOfDigits + 9
 + int* table = (int*)_alloca(sizeOfTable * sizeof(numberOfDigits));​ 
 + table[0] ​0; 
 + table[1] = 2; 
 + for (int i = sizeOfTable - 1; i > 0; i--
 + table[i] = 1; 
 + }
  
-auto pw estimate_function_time(power_by_int<​long double>1.0002, 1000000); + std::​ostringstream output; 
-std::cout << "​Computing 1.02^100000=" ​<< ​pw.second << " in " << pw.first.count() << " ticks.\n"​;+ int x 0; 
 + table[1] = 2; 
 + for (; sizeOfTable ​9; sizeOfTable--) 
 +
 + for (int i = sizeOfTable - 1; i > 0; i--) 
 +
 + table[i] = x % i
 + 10 * table[i - 1] + x / i; 
 +
 + output ​<< ​x; 
 +
 + return output.str(); 
 +}
  
 +int main()
 +{
 + std::​string value = computeE(100);​
 + std::cout << "e with " << 100 << " decimals\n"​ << value << std::endl;
 +}
 </​code>​ </​code>​
 +</​hidden>​
 +===== Question n°2 =====
  
 +Nous constatons que calculer 10000 ou 20000 décimales de e, cela prend du temps. Nous souhaitons transformer cela en une fonction asynchrone à l’aide de la fonction [[http://​en.cppreference.com/​w/​cpp/​thread/​async|std::​async]].
  
-A votre avis ? Est-ce que le compilateur à générer ​le code au moment de la compilation ?+Ecrire ​le code transformant la précédente fonction en une fonction asynchrone en utilisant ​la fonction [[http://​en.cppreference.com/​w/​cpp/​thread/​async|std::​async]].
  
 +Au lieu d'​appeller directement la fonction ​ ''​computeE'',​ nous appellons la fonction ''​computeE''​ au travers d'un appel à la fonction ''​std::​async''​ qui va exécuter la fonction ''​computeE''​ de manière asynchone et retourner un objet de type ''​std::​future<​string>''​ qui va permettre de savoir si le résultat et disponible et aussi d'​avoir la valeur du résultat quand celui-ci sera disponible.
  
-===== Question 2 : ===== 
- 
-En fait, nous pouvons aider naivement le compilateur en faisant bien apparaître le paramètre constant : 
- 
-<code cpp> 
-  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";​ 
-</​code>​ 
- 
- 
-Est-ce que cela améliore les résultats ? Tenter d'​expliquer pourquoi ? 
- 
- 
-===== Question 3 : ===== 
- 
-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 : 
  
 +<hidden Correction>​
 <code cpp> <code cpp>
-constexpr long double factorial(int n)+void display(std::​future<​std::​string>&​ aFutureValue, ​int theDecimals)
 { {
-    return n == 0 ? 1 : n * factorial(n - 1);+ aFutureValue.wait();​ 
 + std::cout << "e with " << theDecimals << " decimals\n" << aFutureValue.get() << std::endl;
 } }
  
 int main() int main()
 { {
-    auto res factorial(100); + std::​future<​std::​string>​ eWidth20000 ​std::async(std::​launch::​async,​ &​computeE,​ 20000); 
-    std::cout << res << "​\n"​;+ std::future<std::​string>​ eWidth100000 = std::​async(std::​launch::​async,​ &​computeE,​ 100000); 
 + display(eWidth20000,​ 20000); 
 + display(eWidth100000,​ 100000);
 } }
 </​code>​ </​code>​
 +</​hidden>​
  
-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 : +=====  Question n°3 ===== 
- +
-<code cpp> +
-int main() +
-+
-    auto res factorial(100);​ +
-    std::cout << res << "​\n";​ +
-+
-</​code>​ +
- +
-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.+
  
 +Lancer deux calculs asynchrones,​ l’un calculant les 1000 premières décimales, l’autre les 10000 premières décimales et afficher les résultats dès que ceux-ci sont disponibles.
  
 <hidden Correction>​ <hidden Correction>​
- auto c_factorial_100 = []() { constexpr auto res = factorial(100);​ return res; }; +La fonction ''​main''​ précédente effectue déjà ce calcul.
- fn = estimate_function_time(c_factorial_100);​ +
- std::cout << "​Computing fact(100)="​ << fn.second << " in " << fn.first.count() << " ticks.\n";​ +
- +
- auto c_power_10002_100000 = []() { constexpr auto res = power_by_int<​long double>​(1.0002,​ 100000); return res; }; +
- pw = estimate_function_time(power_10002_100000);​ +
- std::cout << "​Computing 1.02^1000000="​ << pw.second << " in " << pw.first.count() << " ticks.\n";​ +
 </​hidden>​ </​hidden>​
- 
- 
-===== Question 4 : ===== 
- 
-Tester le code suivant avec un compilateur C++20: 
- 
-<code cpp> 
-template<​double value, int power> 
-struct constant_value 
-{ 
-    static constexpr long double constant() { constexpr auto result = power_by_int(value,​ power); return result; } 
-}; 
- 
-</​code>​ 
- 
-et appeller cette fonction comme suit: 
- 
-<code cpp> 
- auto pw_c = estimate_function_time(pre_computed_value<​1.0002,​ 100000>::​pow);​ 
- std::cout << "​Computing 1.02^1000000="​ << pw_c.second << " in " << pw_c.first.count() << " ticks.\n";​ 
-</​code>​ 
- 
-Expliquer ce qui se passe ? Et pourquoi ce résultat. 
- 
- 
- 
- 
  
  
in204/tds/sujets/td9/part3.1636374275.txt.gz · Last modified: 2021/11/08 12:24 by bmonsuez