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;


并发

比传统的&lt;random&gt; 更喜欢&lt;random&gt; 的一个更重要的原因是现在非常清楚如何使随机数生成线程安全:或者为每个线程提供其自己的线程本地引擎,播种在线程本地种子,或同步访问引擎对象。

杂项

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 可以看出作者不了解如何使用 中的功能。【参考方案2】:

随机数生成器是一个方程,给定一个数字,它会给你一个新数字。通常,您要么提供第一个数字,要么提供从系统时间之类的东西中提取的数字。

每次您要求一个新数字时,它都会使用前一个数字来执行等式。

如果随机数生成器倾向于比其他数字更频繁地生成相同的数字,则认为它不是很好。即,如果你想要一个介于 1 和 5 之间的随机数,并且你有这样的数字分布:

1:1% 2: 80% 3: 5% 4: 5% 5:9%

2 比任何其他数字都更频繁地生成,因此它比其他数字更有可能被生成。如果所有数字都一样,那么您每次都有 20% 的机会获得每个数字。换一种说法,上面的分布很不均匀,因为偏爱2。所有 20% 的分布都是均匀的。

通常,如果您想要一个真正的随机数,您会从天气或其他自然来源而不是随机数生成器中提取数据。

【讨论】:

大多数随机数生成器确实会生成良好的均匀分布。它们不是随机的。问题是它们是计算出来的,因此您可以猜测序列中给定足够数量的下一个数字(这一事实使它们不利于安全,因为需要真正的随机数)。对于游戏和其他东西,你应该没问题。 我很确定 OP 正在询问有关 C++ 标头中提供的设施的具体信息。这个答案甚至没有解决编程问题,更不用说 C++了。 @Martin:安全不一定需要真正随机数的来源。计数器模式下的 AES(例如)可以做得很好,即使它是确定性的。它需要密钥中有合理数量的熵,但不需要任何真正的随机性。 @Benjamin Lindley:没关系。只是重读并意识到我错了。

以上是关于C++11中的随机数生成:如何生成,它是如何工作的? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

如何在C中的两个数字之间生成随机数? (内核)[重复]

如何生成保存到数组中的随机字符串? c# [重复]

关于Python中的随机数生成步骤和随机数质量

如何获得用于生成随机数的范围?

编程:如何生成一组随机数字?

c语言中如何产生1或0随机数