这个问题太宽泛了,无法给出完整的答案,但让我挑几个有趣的点:
为什么“同样可能”
假设您有一个简单的随机数生成器,它以相等的概率生成数字 0、1、...、10(将其视为经典的 rand())。现在你想要一个 0、1、2 范围内的随机数,每个随机数都具有相等的概率。你的下意识反应是接受rand() % 3。但是等等,余数 0 和 1 比余数 2 出现的频率更高,所以这是不正确的!
这就是为什么我们需要适当的分布,它采用均匀随机整数的源并将它们转换为我们想要的分布,例如示例中的Uniform[0,2]。最好把它留给一个好的图书馆!
引擎
因此,所有随机性的核心是一个良好的伪随机数生成器,它生成一系列均匀分布在某个区间上的数字,并且理想情况下具有很长的周期。 rand() 的标准实现通常不是最好的,因此有一个选择是件好事。 Linear-congruential 和 Mersenne twister 是两个不错的选择(LG 实际上也经常被 rand() 使用);再说一次,让图书馆来处理是件好事。
工作原理
简单:首先,设置一个引擎并为其播种。种子完全确定“随机”数字的整个序列,因此 a) 每次使用不同的数字(例如取自 /dev/urandom),并且 b) 如果您希望重新创建随机选择序列,请存储种子。
#include <random>
typedef std::mt19937 MyRNG; // the Mersenne Twister with a popular choice of parameters
uint32_t seed_val; // populate somehow
MyRNG rng; // e.g. keep one global instance (per thread)
void initialize()
{
rng.seed(seed_val);
}
现在我们可以创建分布了:
std::uniform_int_distribution<uint32_t> uint_dist; // by default range [0, MAX]
std::uniform_int_distribution<uint32_t> uint_dist10(0,10); // range [0,10]
std::normal_distribution<double> normal_dist(mean, stddeviation); // N(mean, stddeviation)
...并使用引擎创建随机数!
while (true)
{
std::cout << uint_dist(rng) << " "
<< uint_dist10(rng) << " "
<< normal_dist(rng) << std::endl;
}
并发
比传统的<random> 更喜欢<random> 的一个更重要的原因是现在非常清楚如何使随机数生成线程安全:或者为每个线程提供其自己的线程本地引擎,播种在线程本地种子,或同步访问引擎对象。
杂项
-
interesting article 在 codeguru 上的 TR1 随机。
-
Wikipedia 有一个很好的总结(感谢@Justin)。
- 原则上,每个引擎都应该定义一个
result_type,这是用于种子的正确整数类型。我想我曾经有一个错误的实现,这迫使我在 x64 上将 std::mt19937 的种子强制为 uint32_t,最终这应该被修复,你可以说 MyRNG::result_type seed_val,从而使引擎很容易更换。