在C ++ 11中生成随机数,如何生成,它们是如何工作的?
我最近遇到了用C ++ 11生成随机数的新方法,但无法消化我读到的关于它的文章(引擎是什么,math术语像分布,“所有生成的数据都是同等可能的 ”)。
那么谁能解释一下他们是什么,他们是什么意思,怎么产生,他们是如何工作的? 等等(你可以在一个关于随机数生成的常见问题解答中把它全部叫做)。
这个问题太广泛了,没有一个完整的答案,但让我挑选一些有趣的观点:
为什么“同样可能”
假设你有一个简单的随机数生成器,它们生成的数字分别为0,1,…,10,它们的概率相等(可以认为这是经典的rand()
)。 现在你需要一个0,1,2的随机数,每个数的概率是相等的。 你的下意识的反应将是rand() % 3
。 但是等待,剩余的0和1比剩下的2更频繁出现,所以这是不正确的!
这就是为什么我们需要适当的分布 ,这个分布需要统一随机整数的来源,并把它们变成我们所期望的分布,如例子中的Uniform[0,2]
。 最好把这个留给一个好的图书馆!
引擎
因此,所有随机性的核心是一个很好的伪随机数发生器,它产生一个在一定的时间间隔内均匀分布的数字序列,理想情况下它具有很长的周期。 rand()
的标准实现往往不是最好的,因此有一个select是很好的。 线性同余和Mersenne捻线是两个不错的select(LG实际上也经常被rand()
使用)。 再次,让图书馆处理这件事情是很好的。
怎么运行的
简单:首先,build立一个引擎并播种。 种子完全决定了整个序列的“随机”数字,所以a)每次使用一个不同的数字(例如从/dev/urandom
),并且b)如果你想重新创build一个随机select序列,存储种子。
#include <random> typedef std::mt19937 MyRNG; // the Mersenne Twister with a popular choice of parameters uint32_t seed_val; // populate somehow MyRNG rng; // eg keep one global instance (per thread) void initialize() { rng.seed(seed_val); }
现在我们可以创build分布:
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)
…并使用引擎创build随机数字!
while (true) { std::cout << uint_dist(rng) << " " << uint_dist10(rng) << " " << normal_dist(rng) << std::endl; }
并发
与传统的rand()
,更喜欢<random>
一个更重要的原因是,现在非常清楚明白如何使随机数生成线程安全:为每个线程提供自己的线程本地引擎,本地种子,或者同步对引擎对象的访问。
杂项
- 一个有趣的文章,关于在codeguru随机TR1。
- 维基百科有一个很好的总结(谢谢,@Justin)。
- 原则上,每个引擎都应该键入一个
result_type
,这是用于种子的正确的整数types。 我想我有一个错误的执行一次,迫使我迫使种子std::mt19937
到x64的uint32_t
,最终这应该是固定的,你可以说MyRNG::result_type seed_val
,从而使引擎非常容易replace。
随机数发生器是一个方程,给定一个数字,会给你一个新的数字。 通常你要么提供第一个数字或从系统时间的东西拉。
每次你要求一个新的号码,它使用以前的号码执行方程。
如果一个随机数字发生器有比其他数字更频繁地产生相同数字的倾向,那么它就不是很好。 即如果你想要一个1到5之间的随机数,并且你有这个数字分布:
- 1:1%
- 2:80%
- 3:5%
- 4:5%
- 5:9%
2是比其他任何数字更频繁地产生的,因此比其他数字更有可能产生。 如果所有的数字都是一样的,那么每次都有20%的机会获得每个数字。 换句话说,上述分配是非常不平衡的,因为2是有利的。 所有20%的分配将是均匀的。
通常情况下,如果你想要一个真正的随机数,你会从天气或其他自然资源,而不是随机数发生器的东西拉数据。