تغليف Boost :: عشوائي لسهولة الاستخدام لاستبدال Rand ()

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

  •  26-09-2019
  •  | 
  •  

سؤال

بالنسبة لبرنامجي ، أحتاج إلى أعداد صحيحة عشوائية زائفة مع نطاقات مختلفة. حتى الآن استخدمت وظيفة Rand () ولكن لديها قيود.

لقد وجدت أن Boost :: Random Library بديل أفضل بكثير ولكني لم أرغب في إنشاء مولدات عشوائية في كل مكان.
(أحتاج إلى أعداد صحيحة عشوائية في العديد من الفئات ، لأنه برنامج اختبار الإجهاد يجعل كل قرار عازبًا زائفًا ( -> يجب أن يكون تشغيل الاختبار قابلاً للتكرار عن طريق تحديد نفس بذرة البدء)).

لهذا السبب قمت بتثبيت 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 ++ وأرغب في تحسين مهاراتي ، وقد وجدت أن Overflow هو أفضل مكان للحصول على مشورة عالية الجودة)

هل كانت مفيدة؟

المحلول

أظهر جو غوتيرين المشكلة ، ومع ذلك لم يقدم أي حل :)

المشكلة في الحالة المشتركة هي عدم وجود إعادة إدخال: أي أن تنفيذ نفس الطريقة لا يوفر نفس النتيجة. هذا أمر بالغ الأهمية بشكل خاص في المواقف المتعددة المتقدمة لأن الدولة العالمية قد لا تتغير دائمًا في نفس النقطة في البرنامج ، مما يؤدي إلى نتائج غير متناسقة من شوط إلى آخر.

الحل هو أن كل محاكاة يجب أن يكون لها "حالة" خاصة بها وبعد ذلك ستتجنب الحالة المشتركة.

يمكن تحقيق ذلك بعدة طرق: لا يزال بإمكانك استخدام حالة "عالمية" ولكن تجعلها محلية إلى مؤشر ترابط ، على سبيل المثال ، وبالتالي لن تخطو مؤشرات الترابط على أصابع بعضها البعض.

ومع ذلك ، فإن النسخة المنظف تتكون من تخزين هذه الحالة في مكان ما ، والطريقة الأسهل هي الحصول على نوع من Context الطبقة ، التي تم تأسيسها مرة واحدة لكل محاكاة ، والتي هي مجموعة من حالة المحاكاة (للحالة على مستوى المحاكاة).

مع أخذ ذلك في الاعتبار:

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 مثيل حول المحاكاة الخاصة بك ، ويمكنك تشغيل أكبر عدد ممكن من التوازي.

نصائح أخرى

لقد قمت بلف مولدك بشكل أساسي في المفرد, ، تقديم جميع المشكلات التي تحملها المفردات والمتغيرات العالمية. على سبيل المثال ، ستواجه صعوبة في إجراء اختبارات إجهاد متعددة بشكل متوازٍ ، حيث أن تنفيذك ليس مؤلمًا.

لكن المشكلة الرئيسية التي أراها هي أن غلافك ليس أبسط من مجرد استخدام Boost :: Random بدون Wrapper.

ربما يمكنك تجنب Get(). هذا شخصي بحت ، بالنسبة لي. أفضل آلية استدعاء مثل Random::Seed() و Random::Next() أو Random::Next(min,max). لا يوجد الكثير من الوظائف بشكل عشوائي حتى تتمكن من جعلها جميع وظائف ثابتة.

إليك تطبيق بسيط. لكن ضع في اعتبارك أن هذا يفكر في أنك تستخدم هذا في بيئة واحدة. بالنسبة للبيئة المتعددة الخيوط ، من الأفضل ألا يكون لها كفرد.

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;

فيما يلي نسخة من التغليف:

#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();
}

أود أن أقول أن هذا يبدو جيدًا - وبهذه الطريقة يمكنك بسهولة استبدال جيلك العشوائي في حالة الحاجة.

يمكنك أيضًا تجربة شيء مثل إنشاء كيان في حاوية وخلطها العشوائي.

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());
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top