C ++ 11中的随机数生成:如何生成,它如何工作?[关闭]


102

最近,我遇到了一种在C ++ 11中生成随机数的新方法,但是无法消化我所读到的论文(该引擎是什么,数学术语就像“ 分布”,“产生的所有整数均可能相等 ”)。

所以任何人都可以解释一下

  • 这些是什么?
  • 他们是什么意思?
  • 怎么产生的?
  • 他们如何工作?
  • 等等

您可以在一个有关随机数生成的常见问题解答中将其全部调用。


6
在不知道分布是什么的情况下询问RNG就像在不知道表达式是什么的情况下询问表达式解析器一样... C ++ 11中的RNG库面向的是那些了解一些统计信息并且比由生成的平面分布产生更大需求的人们rand,您应该快速了解Wikipedia的一些基本统计信息和RNG概念,否则,将很难向您解释<random>其各个部分的原理和用法。
Matteo Italia

26
@Matteo:几乎没有。孩子可以理解骰子产生随机数的概念,而无需了解分布是什么。
本杰明·林德利

3
@Benjamin:那是他的理解停止的地方,这只是第一步(引擎),甚至不了解为什么生成平坦分布很重要。在不了解分布和其他统计概念的情况下,该库的所有其余部分仍然是个谜。
Matteo Italia

Answers:


142

这个问题太宽泛,无法给出完整的答案,但让我挑几个有趣的观点:

为什么“同样可能”

假设您有一个简单的随机数生成器,它以相等的概率生成数字0、1,...,10(将其视为经典rand())。现在,您需要0、1、2范围内的随机数,每个概率均等。你的下意识反应是采取rand() % 3。但是,等等,余数0和1比余数2更频繁地出现,所以这是不正确的!

这就是为什么我们需要适当的分布,它需要一个均匀的随机整数源,并将它们变成我们想要的分布,如Uniform[0,2]示例中所示。最好把它留给一个好的图书馆!

引擎

因此,所有随机性的核心是一个好的伪随机数生成器,该生成器生成一个在一定间隔内均匀分布的数字序列,理想情况下,其周期很长。标准的实现rand()通常不是最好的,因此最好有一个选择。线性同余和Mersenne捻线机是两个不错的选择(LG实际上也经常被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>与传统rand()方法相比,更重要的一个原因是,现在很清楚并且很明显如何使随机数生成线程安全:为每个线程提供自己的,线程本地的引擎,以线程本地的种子为种子或同步访问到引擎对象。

杂项

  • 关于Codeguru上TR1 random 的有趣文章
  • Wikipedia有一个很好的摘要(感谢@Justin)。
  • 原则上,每个引擎都应typedef a result_type,这是用于种子的正确整数类型。我认为我曾经有一个错误的实现,迫使我强制将种子强制移植std::mt19937uint32_tx64上,最终应该将其修复,您可以说MyRNG::result_type seed_val,这样就很容易更换引擎。

再一次,Kerrek用比我正在研究的答案更好的答案击败了我。+1
贾斯汀(Justin)2011年

@Justin:我敢肯定我错过了很多事情,请随时为该主题添加更多内容!:-)
Kerrek SB 2011年

13
对于“以某种方式填充”部分,我认为std::random_device值得一提,而不是/dev/urandom
Cubbi

2
std::random_device可以在此处找到一个示例。
WKS 2012年

1
Wikipedia文章中的代码有错误。random和random2相同。从代码片段中的注释可以明显看出,作者不了解如何使用<random>中的功能。
user515430 2014年

3

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

每次您要求一个新数字时,它都会使用先前的数字执行方程式。

如果随机数生成器倾向于产生比其他数字更多的相同数字,则认为它不是很好。也就是说,如果您想要一个介于1到5之间的随机数,并且您具有以下这种数字分布:

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

2比任何其他数字生成FAR的频率更高,因此比其他数字更可能生成FAR。如果所有数字都一样,您将有20%的机会每次获得每个数字。换句话说,由于赞成2,所以上述分布非常不均匀。所有20%的分布都是偶数。

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


8
大多数随机数生成器的确会生成良好的均匀分布。他们只是不是随机的。问题在于它们是经过计算的,因此您可以猜测序列中给定足够数量的下一个数字(这一事实使它们对于需要真正随机数的安全性不利)。对于游戏和其他东西,您应该没问题。
马丁·约克

5
我非常确定OP正在询问有关C ++ <random>标头中提供的功能的特定信息。这个答案甚至没有解决编程问题,更不用说C ++了。
本杰明·林德利

1
@马丁:安全性不一定需要真正随机数的来源。即使是确定性的,计数器模式下的AES(例如)也可以做得很好。它要求密钥中有合理数量的熵,但不需要任何真正的随机性。
杰里·科芬

@Benjamin Lindley:没关系。重新阅读并意识到我错了。
2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.