C++11中的随机数生成:如何生成,它是如何工作的? [关闭]
Posted
技术标签:
【中文标题】C++11中的随机数生成:如何生成,它是如何工作的? [关闭]【英文标题】:Random number generation in C++11: how to generate, how does it work? [closed] 【发布时间】:2011-10-30 03:40:27 【问题描述】:我最近遇到了在 C++11 中生成随机数的新方法,但无法理解我读到的 papers(那个 engine 是什么,数学术语如 distribution,“所有产生的整数都同样可能”)。
谁能解释一下
它们是什么? 它们是什么意思? 如何生成? 它们是如何工作的? 等您可以在一个关于随机数生成的常见问题解答中一一解决。
【问题讨论】:
在不知道什么是分布的情况下询问 RNG 就像在不知道表达式是什么的情况下询问表达式解析器...... C++11 中的 RNG 库面向了解一些统计数据并拥有比rand
生成的平面分布更大的需求,你应该快速浏览一下***,了解一些基本的统计和RNG 概念,否则很难向你解释<random>
的基本原理及其各个部分的用法.
@Matteo:几乎没有。孩子可以掌握骰子产生随机数的概念,而无需了解分布是什么。
@Benjamin:这就是他的理解停止的地方,这只是第一步(引擎),甚至不理解为什么它们生成平坦分布很重要。如果不了解分布和其他统计概念,库的所有其余部分仍然是一个谜。
【参考方案1】:
这个问题太宽泛了,无法给出完整的答案,但让我挑几个有趣的点:
为什么“同样可能”
假设您有一个简单的随机数生成器,它以相等的概率生成数字 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
,从而使引擎很容易更换。
【讨论】:
再一次,Kerrek 以比我正在研究的答案更好的答案击败了我。 +1 @Justin:我确定我错过了很多东西,请随时为这个主题添加更多方面! :-) 对于“以某种方式填充”部分,我认为std::random_device
值得一提,而不是/dev/urandom
std::random_device
的示例可以在 here 找到。
***文章中的代码有问题。 random 和 random2 是相同的。从代码 sn-p 中的 cmets 可以看出作者不了解如何使用 随机数生成器是一个方程,给定一个数字,它会给你一个新数字。通常,您要么提供第一个数字,要么提供从系统时间之类的东西中提取的数字。
每次您要求一个新数字时,它都会使用前一个数字来执行等式。
如果随机数生成器倾向于比其他数字更频繁地生成相同的数字,则认为它不是很好。即,如果你想要一个介于 1 和 5 之间的随机数,并且你有这样的数字分布:
1:1% 2: 80% 3: 5% 4: 5% 5:9%2 比任何其他数字都更频繁地生成,因此它比其他数字更有可能被生成。如果所有数字都一样,那么您每次都有 20% 的机会获得每个数字。换一种说法,上面的分布很不均匀,因为偏爱2。所有 20% 的分布都是均匀的。
通常,如果您想要一个真正的随机数,您会从天气或其他自然来源而不是随机数生成器中提取数据。
【讨论】:
大多数随机数生成器确实会生成良好的均匀分布。它们不是随机的。问题是它们是计算出来的,因此您可以猜测序列中给定足够数量的下一个数字(这一事实使它们不利于安全,因为需要真正的随机数)。对于游戏和其他东西,你应该没问题。 我很确定 OP 正在询问有关 C++以上是关于C++11中的随机数生成:如何生成,它是如何工作的? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章