我有一个类需要在几个不同的成员方法中使用随机数。我正在使用C++11
,我认为在每种方法中新创建一个随机数生成器是不可行的。
是否可以通过将随机数生成器设为类的成员属性或 typedef 来在类中共享随机数生成器,同时仍确保良好的随机性?
我该怎么做,也许你可以给我举一个小例子?我应该在哪里为随机引擎设置种子,我想使用Mersenne twister
具有不同类型分布(normal
& uniform
)的引擎。
我有一个类需要在几个不同的成员方法中使用随机数。我正在使用C++11
,我认为在每种方法中新创建一个随机数生成器是不可行的。
是否可以通过将随机数生成器设为类的成员属性或 typedef 来在类中共享随机数生成器,同时仍确保良好的随机性?
我该怎么做,也许你可以给我举一个小例子?我应该在哪里为随机引擎设置种子,我想使用Mersenne twister
具有不同类型分布(normal
& uniform
)的引擎。
引擎和分布是值,可以像其他具有值类型的对象一样成为成员。
您应该在创建引擎时播种引擎,这意味着,如果它是成员,则在构造对象时。我的示例默认使用类内初始化程序random_device
为引擎播种。它还允许指定种子,以获得可重复的、可测试的结果。
我会避免暴露太多的实现细节,比如提供更完整的接口来与引擎交互,因为这会破坏封装。这些应该是实现的内部隐藏细节。
std::mt19937 make_seeded_engine() {
std::random_device r;
std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()};
return std::mt19937(seed);
}
struct Foo {
std::mt19937 eng = make_seeded_engine();
std::uniform_int_distribution<> dist1 {1, 20};
std::uniform_real_distribution<> dist2 {0.0, 100.0};
Foo() = default;
template<typename SeedSeq>
Foo(SeedSeq &&seed) : eng(seed) {}
int bar() {
return dist1(eng);
}
double baz() {
return dist2(eng);
}
};
您至少需要在两次使用之间存储引擎,因为随机序列均匀分布的保证仅适用于对同一引擎对象的重复调用序列。无法保证使用不同引擎产生的序列。
事实上,发行版也是如此,尽管我不知道每次创建新发行版实际上会产生不正确结果的实现(但是,有些实现中发行版出于各种原因缓存值,因此每次创建发行版都可以表现更差并产生不同的序列)。
例如,用于计算正态分布的常用算法一次产生两个值。`std::normal_distribution 的实现会执行此操作并缓存第二个值以使用其他所有调用。下面的程序展示了这一点。
#include <iostream>
#include <random>
int main() {
typedef std::mt19937 Engine;
typedef std::normal_distribution<> Distribution;
Engine eng(1);
Distribution dist;
for (int i=0; i<10; ++i)
std::cout << dist(eng) << ' ';
std::cout << '\n';
eng.seed(1);
for (int i=0; i<10; ++i)
std::cout << Distribution()(eng) << ' ';
std::cout << '\n';
}
使用 VC++2012 我得到输出:
0.156066 0.3064 -0.56804 -0.424386 -0.806289 -0.204547 -1.20004 -0.428738 -1.18775 1.30547
0.156066 -0.56804 -0.806289 -1.20004 -1.18775 -0.153466 0.133857 -0.753186 1.9671 -1.39981
请注意,每次迭代创建新分布时生成的序列仅包含使用单个分布生成的序列的所有其他值。