[英]Encapsulating boost::random for ease of usage to replace rand()
对于我的程序,我需要具有不同范围的伪随机整数。 到目前为止,我使用了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 ++的新手,想要提高我的技能,我发现Stack溢出是获得高质量建议的最佳场所)
你基本上把你的生成器包裹在一个单例中 ,介绍了单例和全局变量带来的所有问题。 例如,您很难并行运行多个压力测试,因为您的实现不是线程安全的。
但是我看到的主要问题是你的包装并不比仅使用boost :: random更简单。
Joe Gauterin演示了这个问题,但它没有提供任何解决方案:)
共享状态的问题是没有重入:即,执行两次相同的方法不会提供相同的结果。 这在多线程情况下尤其重要,因为全局状态可能并不总是在程序中的同一点发生变化,从而导致从一次运行到另一次运行的结果不一致。
解决方案是每个模拟应该有自己的“状态”,然后你将避免共享状态。
这可以通过多种方式实现:例如,您仍然可以使用“全局”状态但将其设置为线程的本地状态,因此线程不会踩到彼此的脚趾。
然而,更干净的版本在于将此状态存储在某处,更简单的方法是使用某种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
实例,并且可以并行运行任意数量的实例。
你可以避免Get()
。 对我来说,这纯粹是主观的。 我更喜欢一个调用机制,如Random::Seed()
和Random::Next()
或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;
以下是我的封装版本:
#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 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.