Encapsulant boost :: aléatoire pour la facilité d'utilisation pour remplacer rand ()

StackOverflow https://stackoverflow.com/questions/3617317

  •  26-09-2019
  •  | 
  •  

Question

pour mon programme j'ai besoin pseudo entiers aléatoires avec des gammes différentes. Jusqu'à présent, j'utilisé la fonction rand (), mais il a ses limites est tout.

Je trouve le boost :: bibliothèque aléatoire pour être un meilleur remplacement, mais je ne voulais pas créer des générateurs aléatoires dans tous les sens.
. (J'ai besoin des nombres entiers aléatoires dans de nombreuses classes, car il est un logiciel de test de stress qui rend pseudo-aléatoire toutes les décisions (-> un test doit être répété en réglant la même graine de démarrage))

Voilà pourquoi je capsulé boost :: loin au hasard dans ma propre classe.

L'idée est de faciliter l'utilisation de sorte qu'il est presque aussi simple que la méthode C ++ rand ()

#include "boost/shared_ptr.hpp"
#include "boost/random.hpp"

class Random{
public:
   typedef boost::shared_ptr< Random > randomPtr;
   typedef boost::mt19937 randomGeneratorType;

   static randomPtr Get(){
      static randomPtr randomGen( new RandomGenerator() );
      return randomGen;
   }

   void SetSeed(int seed){
      randomGenerator.seed( seed );
   }

   int Random( int lowerLimit, int upperLimit ){
   boost::uniform_int<> distribution( lowerLimit, upperLimit );
   boost::variate_generator< randomGeneratorType&, boost::uniform_int<> >
   LimitedInt( randomGenerator , distribution );
   return LimitedInt();
   }

private:
   // prevent creation of more than one object of the LogManager class
   // use the Get() method to get a shared_ptr to the object
  Random():
    randomGenerator() //initialize randomGenerator with default constructor
  {}

  RandomGenerator( const RandomGenerator& orig ){};

  randomGeneratorType randomGenerator;
};

générer un nombre aléatoire dans une plage donnée sera désormais aussi facile que

#include "Random.h"
  Random::Get()->SetSeed( 123123 );  // If you want to make the run repeatable
  int dice = Random::Get()->Random(1,6);

Question: Y at-il quelque chose de mal avec cette façon de générer des nombres aléatoires?
Grand frais généraux que je ne connaissais pas?
Pure Evil ou d'une technique de programmation dépassée?

(je suis encore nouveau pour c ++ et que vous souhaitez améliorer mes compétences, et je l'ai trouvé que le débordement de pile est le meilleur endroit pour obtenir des conseils de haute qualité)

Était-ce utile?

La solution

Joe Gauterin a démontré la question, mais il n'a pas offert de solution:)

Le problème avec l'état partagé est l'absence de reentrance: par exemple, exécuter deux fois la même méthode ne fournit pas le même résultat. Ceci est particulièrement important dans les situations multithread parce que l'état global ne peut pas toujours changer au même point dans le programme, ce qui conduit à des résultats incohérents d'une course à l'autre.

La solution est que chaque simulation doit avoir son propre « État » et vous éviterait l'état partagé.

Ceci peut être accompli dans un certain nombre de façons. Vous pouvez toujours utiliser un état « global », mais le rendre local à un fil, par exemple, donc les fils ne serait pas marcher sur les pieds des autres

La version plus propre, cependant, consiste à stocker ce quelque part de l'État, et la façon plus facile est d'avoir une sorte de classe Context, instancié une fois par simulation, et qui est un agrégat de l'état de la simulation (pour la simulation à l'échelle état).

Avec cela à l'esprit:

class Context
{
public:
  typedef boost::mt19937 RandomGeneratorType;

  void SetSeed(int seed){
     rg.seed( seed );
  }

  int Next( int lowerLimit, int upperLimit ) {
    boost::uniform_int<> distribution( lowerLimit, upperLimit );
    boost::variate_generator< randomGeneratorType&, boost::uniform_int<> >
    LimitedInt( rg, distribution );
    return LimitedInt();
  }

private:
  RandomGeneratorType rg;
};

Ensuite, passez l'instance de Context autour de votre simulation, et vous pouvez exécuter autant que vous le souhaitez en parallèle.

Autres conseils

Vous avez essentiellement enveloppé votre générateur dans un singleton, introduisant tous les problèmes qui singletons et portent des variables globales. Par exemple, vous auriez du mal à obtenir de multiples tests de résistance en cours d'exécution en parallèle, comme la mise en œuvre est pas sûre.

Mais le principal problème que je vois est que votre emballage n'est pas plus simple que d'utiliser simplement boost :: aléatoire sans l'emballage.

Vous pouvez probablement éviter Get(). Ceci est purement subjectif, pour moi. Je préférerais un mécanisme d'appel comme Random::Seed() et Random::Next() ou Random::Next(min,max). Il n'y a pas trop de fonction au hasard pour que vous puissiez les faire toutes les fonctions statiques.

Voici une implémentation simple. Mais gardez à l'esprit que cela vous envisage utilisez ce dans un environnement monothread. Pour un environnement multi-thread, il est préférable de ne pas avoir comme un singleton.

class Random
{
public:
    typedef boost::mt19937 RandomGeneratorType;

    static void Seed(int seed)
    {
        s_randGen.seed(seed);
    }

    static int NextInt(int min_val, int max_val)
    {
        boost::uniform_int<> distribution(min_val, max_val);boost::variate_generator< randomGeneratorType&, boost::uniform_int<> >
        return LimitedInt( s_randGen , distribution );;
    }
private:
    static RandomGeneratorType s_randGen;
};

Random::RandomGeneratorType Random::s_randGen;

Voici ma version d'encapsulation:

#include <boost/random.hpp>
#include <ctime>  


int getRandomIntValue(int min, int max)
{
    static boost::minstd_rand gen((unsigned int)std::time(NULL));
    boost::uniform_int<int> dist(min, max);
    boost::variate_generator<
        boost::minstd_rand&,
        boost::uniform_int<int>> combgen(gen, dist);

    return combgen();
}

Je dirais que cela ressemble bien -. De cette façon vous pouvez facilement remplacer votre algo de génération aléatoire devrait-il être nécessaire

Vous pouvez également essayer quelque chose comme créer une entité dans un récipient et aléatoire aléatoire eux.

void
GenerateRandomString(vector<string>& container,
                     int size_of_string,
                     unsigned long long num_of_records,
                     int thread_id)
{
  srandom(time(0));
  random();
  for(unsigned long long int i=0; i < num_of_records; ++i)
  {
    stringstream str_stream;
    str_stream.clear();
    str_stream << left << setfill('x') << setw(size_of_string-4);
    str_stream << num_of_records+i+1 << "-" << thread_id;
    container.push_back(str_stream.str());
  }
  random_shuffle(container.begin(), container.end());
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top