Mesures – Test 3.0

Cet exemple utilise une version simplifiée de la fonction de mesure de temps présentée dans ../Sujets/AuSecours/Mesurer-le-temps.html et compile avec C++ 17 (ce n'est pas essentiel, mais ça simplifie l'écriture).

#include <vector>
#include <cstdlib>
#include <ctime>
#include <algorithm>
#include <iostream>
#include <chrono>
#include <random>
#include <memory>
using namespace std;
using namespace std::chrono;
template <class F, class ... Args>
   auto test(F f, Args &&... args) {
      auto pre = high_resolution_clock::now();
      auto res = f(std::forward<Args>(args)...);
      auto post = high_resolution_clock::now();
      return pair{ res, post - pre };
   }
struct Parent {
   virtual long long f(int) const = 0;
   virtual ~Parent() = default;
};
struct EnfantFacto : Parent {
   long long f(int n) const {
      auto cumul { 1LL };
      for (int i = 1; i <= n; i++)
         cumul *= i;
      return cumul;
   }
};
struct EnfantSomme : Parent {
   long long f(int n) const {
      auto somme { 0LL };
      for (int i = 1; i <= n; i++)
         somme += i;
      return somme;
   }
};
class OperGen {
   long long cumul {};
   vector<int>::const_iterator cur;
public:
   OperGen(vector<int>::const_iterator it) : cur{ it } {
   }
   template <class U>
      void operator()(const U &operande) {
         cumul += operande.f(*cur++);
      }
   auto valeur() const {
      return cumul;
   }
};
class OperPol {
   long long cumul{};
   vector<int>::const_iterator cur;
public:
   OperPol(vector<int>::const_iterator it) : cur{ it } {
   }
   void operator()(const unique_ptr<Parent> &operande) {
      cumul += operande->f(*cur++);
   }
   auto valeur() const {
      return cumul;
   }
};
int main() {
   enum { NTESTS = 10'000'000 };
   vector<int> v(NTESTS);
   mt19937 rng(random_device{}());
   uniform_int_distribution<int> d10{ 1, 10 };
   uniform_int_distribution<int> d2{ 0, 1 };
   generate_n(begin(v), NTESTS, [&]{ return d10(rng); });
   vector<EnfantFacto> veF;
   vector<EnfantSomme> veS;
   vector<unique_ptr<Parent>> vP;
   vector<int> valFac;
   vector<int> valSom;
   for (int i = 0; i < NTESTS; i++)
      if (d2(rng) == 0) {
         veF.push_back(EnfantFacto{});
         vP.push_back(unique_ptr<Parent>(new EnfantFacto));
         valFac.push_back(v[i]);
      } else {
         veS.push_back(EnfantSomme());
         vP.push_back(unique_ptr<Parent>(new EnfantSomme));
         valSom.push_back(v[i]);
      }
   clog.rdbuf(nullptr);
   auto [r0, dt0] = test([&] {
      return for_each(begin(vP), end(vP), OperPol(begin(v))).valeur();
   });
   auto [r1, dt1] = test([&] {
      auto f = for_each(begin(veF), end(veF), OperGen(begin(valFac)));
      auto s = for_each(begin(veS), end(veS), OperGen(begin(valSom)));
      return f.valeur() + s.valeur();
   });
   // Résultats des tests
   cout << "Calculs sur " << NTESTS << " valeurs...\n"
        << "- polymorphique: "
        << duration_cast<milliseconds>(dt0).count() << " ms.\n"
        << "- generique: "
        << duration_cast<milliseconds>(dt1).count() << " ms." << endl;
   clog << r0 << r1;
}

Quelques résultats suivent. Portez attention aux temps relatifs pour un même compilateur, mais ne comparez pas les compilateurs entre eux, car les exécutions sont faites sur des machines distinctes :

Wandbox (lien) Coliru (lien) Visual Studio 2019 (Release, 32 bits)
Calculs sur 10000000 valeurs...
- polymorphique: 536 ms.
- generique: 243 ms.
Calculs sur 10000000 valeurs...
- polymorphique: 169 ms.
- generique: 107 ms.
Calculs sur 10000000 valeurs...
- polymorphique: 277 ms.
- generique: 211 ms.

Valid XHTML 1.0 Transitional

CSS Valide !