3

私のプログラムでは、異なる範囲の疑似ランダム整数が必要です。今までは rand() 関数を使用していましたが、制限があります。

boost::random ライブラリがはるかに優れた代替手段であることがわかりましたが、ランダムジェネレーターをあちこちに作成したくありませんでした。
(すべての決定を疑似ランダムに行うストレステストソフトウェアであるため、多くのクラスでランダムな整数が必要です(->同じ開始シードを設定することにより、テストの実行を繰り返し可能にする必要があります))。

そのため、boost::random を自分のクラスにカプセル化しました。

この背後にある考え方は、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;
};

特定の範囲内で乱数を生成することは、次のように簡単になります。

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

質問:
この乱数の生成方法に問題はありますか?
私が認識していなかった大きなオーバーヘッド?
純粋な悪か時代遅れのプログラミング技術か?

(私はまだ C++ に不慣れで、スキルを向上させたいと考えています。高品質のアドバイスを得るには、スタック オーバーフローが最適な場所であることがわかりました)

4

6 に答える 6

3

Joe Gauterin がこの問題を示しましたが、解決策はありませんでした :)

共有状態の問題は、再入可能性がないことです。つまり、同じメソッドを 2 回実行しても同じ結果は得られません。これはマルチスレッドの状況では特に重要です。これは、グローバルな状態がプログラムの同じポイントで常に変化するとは限らず、実行ごとに一貫性のない結果が生じる可能性があるためです。

解決策は、各シミュレーションに独自の「状態」を持たせ、共有状態を避けることです。

これはさまざまな方法で実現できます。たとえば、「グローバル」状態を使用してスレッドに対してローカルにすることもできます。これにより、スレッドが互いに足を踏まなくなります。

Contextただし、よりクリーンなバージョンは、この状態をどこかに保存することで構成されます。より簡単な方法は、シミュレーションごとに 1 回インスタンス化され、シミュレーションの状態の集合体である (シミュレーション全体の状態の)ある種のクラスを持つことです。

それを念頭に置いて:

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;
};

次に、Contextシミュレーションでインスタンスを渡すと、必要な数のインスタンスを並行して実行できます。

于 2010-09-01T12:23:47.723 に答える
3

基本的にジェネレーターをsingletonでラップし、singleton とグローバル変数が持つすべての問題を導入しました。たとえば、実装がスレッド セーフではないため、複数のストレス テストを並行して実行するのは困難です。

しかし、私が見る主な問題は、ラッパーなしでboost::randomを使用するよりもラッパーが単純ではないということです。

于 2010-09-01T11:14:58.267 に答える
1

以下はカプセル化の私のバージョンです:

#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();
}
于 2010-11-02T18:27:50.500 に答える
1

おそらく避けることができGet()ます。これは純粋に主観的なものです。Random::Seed()and Random::Next()orのような呼び出しメカニズムを好むでしょうRandom::Next(min,max)。Random にはあまり多くの関数がないため、すべて静的関数にすることができます。

これが簡単な実装です。ただし、これはシングルスレッド環境で使用していることを考慮していることに注意してください。マルチスレッド環境では、シングルトンとして持たない方がよいでしょう。

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;
于 2010-09-01T11:15:31.370 に答える
0

コンテナ内にエンティティを作成してランダムにシャッフルするようなものを試すこともできます。

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());
}
于 2010-09-01T11:46:11.203 に答える
0

これは問題ないように見えます-このようにして、必要に応じてランダム生成アルゴリズムを簡単に置き換えることができます。

于 2010-09-01T11:12:28.097 に答える