C++ 如何引用随机发生器?
我试图在一定范围内生成随机数。我有多个线程中的多个对象将调用这个函数,这个函数在一个单例类中,因此只有一个对象被调用。但我注意到,我的随机数更接近范围的中间值,因此,在前200次通话中,它们彼此接近,然后开始在给定范围内缓慢分散C++ 如何引用随机发生器?,c++,c++11,visual-c++,C++,C++11,Visual C++,我试图在一定范围内生成随机数。我有多个线程中的多个对象将调用这个函数,这个函数在一个单例类中,因此只有一个对象被调用。但我注意到,我的随机数更接近范围的中间值,因此,在前200次通话中,它们彼此接近,然后开始在给定范围内缓慢分散 每次重新实例化和重新设定种子是否有危害 调用的函数?我确实读过,但没有完全理解 理解它 我试图将std::uniform\u real\u distribution dis保留为类变量,但我不断收到错误,即uniform\u real\u distribution不是s
std::uniform\u real\u distribution dis
保留为类变量,但我不断收到错误,即uniform\u real\u distribution
不是std::
的成员,这是为什么std::shared\u ptr\u uniform\u distribution
保留为类变量,但仍然出现错误double-getRandom(Object*foo){
std::随机_装置rnd;
标准:mt19937 gen(rnd());
标准:均匀真实分布分布(0,foo->limit);
双随机=dis(gen);
返回随机;
}
您应该只为随机数生成器设定一次种子。除此之外,您的getRandom
函数是正确的。至于如何在类上下文中使用所有这些,下面是您可以如何做到的:
#include <random>
class RNG
{
public:
RNG::RNG() : gen(std::random_device()()) {} // Seeds the mt19937.
double getRandom(Object* foo){
std::uniform_real_distribution<double> dis(0, foo->limit);
double random = dis(gen);
return random;
}
private:
std::mt19937 gen;
};
#包括
类RNG
{
公众:
RNG::RNG():gen(std::random_device()){}//为mt19937种子。
双getRandom(对象*foo){
标准:均匀真实分布分布(0,foo->limit);
双随机=dis(gen);
返回随机;
}
私人:
标准:mt19937 gen;
};
因此,在程序开始时,实例化一个
RNG
,然后mt19937
将被播种一次。然后,只要在需要随机数的时候调用同一个RNG
。如果要将分布作为成员变量,则必须在每次调用时创建新参数:
#include <random>
#include <iostream>
class Object
{
public:
double limit = 100.0;
};
class MyRandomGen
{
// typedef this for readability
typedef typename std::uniform_real_distribution<double>::param_type param_type;
std::mt19937 gen;
std::uniform_real_distribution<double> dis;
public:
MyRandomGen(): gen(std::random_device()()) {} // seed only once
double getRandom(Object* foo)
{
param_type range {0, foo->limit}; // new distribution parameters
return dis(gen, range);
}
};
int main()
{
Object o;
MyRandomGen gen;
for(auto i = 0; i < 10; ++i)
std::cout << gen.getRandom(&o) << '\n';
}
您可以创建
gen
和rng
静态局部变量。这将确保随机数生成器初始化一次
在您的函数生成器中,每次调用时都会使用新的随机种子重新初始化。将分发作为类成员应该不会有问题。将
std::random_device
的实例作为类成员将是一个问题(至少在许多情况下),因为它无法复制。幸运的是,您并不真正需要它的实例作为类成员,因为(如前所述)您只想调用它一次。由于其他人已经发布了他们关于更正生成器类的想法,我想我也会添加我的想法:
class generator {
std::uniform_real_distribution<double> dis;
std::mt19937 gen;
public:
generator(double lower = 0.0, double upper = 100.0)
: gen(std::random_device()()), dis(lower, upper) {}
double operator()() {
return dis(gen);
}
};
在前20名中达到0.4到95.9的数字似乎涵盖了这一范围
另一方面,在64位编译器上,您可能希望使用
mt19937\u 64
而不是mt19937
,至少作为一项规则。目前的情况是,每次获得另一个随机数时,您都是从random\u设备
中播种mt19937。在这种情况下,您也可以直接从random_设备返回数据。从随机设备进行种子设定的通常原因是对mt19937进行一次种子设定,然后在再次进行种子设定之前获取多个数字。在尝试参考均匀真实分布之前是否包含
?请参见此处的种子设定方法。只做一次@包括天顶是2。听起来好像在类定义之前没有包含
。但您可能希望每次都重新创建发行版(因为foo->limit
每次都可能不同);只需将gen
设为类成员,在初始化时种子设定一次。如果您永远不想重新设定种子并希望它是自包含的,可以将其静态地放在函数中。@NeilKirk这样做包括一个假设,即只在一个上下文中使用。如果他在不同数量的上下文中使用它,输出将根据使用的数量而变化。将它作为一个实例变量,可以为每个用例提供一个随机数生成器,而不会干扰其他生成器。嗨,我想知道使用同一个种子两次(比如1010)播种会产生什么结果,这会与使用同一个数目的种子一次不同吗?@lorniper No(除非您在两个种子之间生成随机数)。@emlai谢谢,事实上我在两个种子之间生成了随机数,这可能会对随机性有害?rnd
不需要是成员,因为它只在构造函数中使用。
48.4072
11.9905
39.0123
49.2113
69.3635
0.369986
19.9654
42.4251
92.9024
29.7522
class generator {
std::uniform_real_distribution<double> dis;
std::mt19937 gen;
public:
generator(double lower = 0.0, double upper = 100.0)
: gen(std::random_device()()), dis(lower, upper) {}
double operator()() {
return dis(gen);
}
};
generator g;
std::generate_n(std::ostream_iterator<double>(std::cout, "\n"), 20, generator());
22.832
82.3414
20.7805
28.9464
6.72104
95.8591
1.92738
70.2699
0.447961
70.591
0.549306
27.9672
10.243
23.0606
76.155
67.6821
63.7346
20.4228
77.9004
39.6607