23

我有一个包含两个随机源的类。

std::random_device rd;
std::mt19937 random_engine;

std::mt19937打电话给std::random_device. 如果我想生成一个数字并且我不关心可重复性,我应该打电话rd()还是random_engine()

在我的特殊情况下,我确信两者都可以正常工作,因为这将在某些网络代码中调用,其中性能不是很重要,结果也不是特别敏感。但是,我对何时使用硬件熵和何时使用伪随机数的一些“经验法则”感兴趣。

目前,我只std::random_device用来播种我的std::mt19937引擎,而我的程序需要的任何随机数生成,我都使用std::mt19937引擎。

编辑:这是我使用这个特定示例的确切含义的解释:

这是一个游戏程序。这个特定的游戏允许用户在与对手开始一轮之前自定义他们的“团队”。设置战斗的一部分涉及将团队发送到服务器。我的程序有几个团队,并使用随机数来确定要加载哪个团队。每场新的战斗都会调用std::random_device播种伪随机数生成器。我记录了战斗的初始状态,其中包括我随机选择的这个团队和初始种子。

我在这个问题中询问的特定随机数是用于随机团队选择(不让对手提前知道我正在使用的团队是有益的,但不是关键任务),但我的我真正寻找的是经验法则。std::random_device如果我不需要我的数字的可重复性,总是使用它是否可以,或者是否存在真正的风险,即用完熵的速度比收集它的速度快?

4

6 回答 6

10

据我所知,标准做法是用计算机计算的数字(但来自一些外部的、不可预测的来源)为随机数生成器播种。您的 rd() 函数应该是这种情况。从那时起,您为所需的每个伪随机数调用伪随机数生成器 (PRNG)。

如果您担心数字不够随机,那么您应该选择不同的 PRNG。熵是一种稀缺而珍贵的资源,应该这样对待。虽然,您现在可能不需要那么多随机数,但将来可能需要;或其他应用程序可能需要它们。您希望该熵在应用程序要求时可用。

听起来,对于您的应用,mersenne twister 可以很好地满足您的需求。玩你的游戏的人不会觉得加载的团队不是随机的。

于 2012-08-06T03:00:05.083 回答
8

如果您不使用它进行加密,那么重复使用由random_engine.

对于这个答案的其余部分,我假设您在网络代码中使用随机数进行加密。总之,mt19937不适合那个用途。

http://en.wikipedia.org/wiki/Mersenne_twister#Disadvantages

随着时间的推移,您可能会泄露信息(可能是间接泄露),这样攻击者就可以开始预测随机数。至少在理论上,但这就是它的意义所在。来自维基百科

...因为这个数字是
产生未来迭代的状态向量的大小)允许人们预测所有未来的迭代。

防止随机数生成信息泄露给用户的一种简单方法是使用单向散列函数,但还有更多。您应该使用为此目的设计的随机数生成器:

http://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator

各种示例(带代码)可在此处找到http://xlinux.nist.gov/dads/HTML/pseudorandomNumberGen.html

于 2012-08-05T15:15:20.037 回答
8

如果您需要模拟或游戏的随机性,那么您正在做的很好。只调用一次随机设备,然后使用随机播种的伪 RNG 执行其他所有操作。作为奖励,您应该将种子值存储在日志文件中,以便稍后重播伪随机序列:

auto const seed = std::random_device()();
// save "seed" to log file
std::mt19937 random_engine(seed);

(对于多线程,在主线程中使用 PRNG 为衍生线程中的进一步 PRNG 生成种子。)

如果出于加密目的需要大量真正的随机性,那么 PRNG 绝不是一个好主意,因为一长串输出包含的随机性比真正的随机性要少得多,也就是说,您可以从一个小的子集中预测所有这些。如果您需要真正的随机性,您应该从一些不可预测的来源(例如热传感器、用户键盘/鼠标活动等)收集它。Unix/dev/random可能是这样一个“真正的随机性”来源,但它可能不会很快填满。

于 2012-08-05T15:18:50.433 回答
3

您可能想看看http://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful,它解释了为什么应该使用 uniform_int_distribution,以及 random_device / mt19937 的相对优势。

在此视频中,Stephan T. Lavavej 特别指出,在 Visual C++ 上,random_device 可用于加密目的。

于 2013-09-11T22:25:57.457 回答
2

答案取决于平台。我似乎记得在 Visual C++ 2010 中,std::random_device 只是 mt19937 以某种未记录的方式播种。

当然,您意识到任何基于随机数生成器的临时加密方案都可能非常弱。

于 2012-08-05T19:09:50.123 回答
-2

假设这不是出于加密目的,关于随机数生成,最重要的是要记住您希望随机数的分布方式以及您期望的范围是多少。

通常库中的标准随机数生成器旨在提供均匀分布。所以数字将介于 0 和一些 RAND_MAX 之间(比如在 32 位机器上是 2^31 -1 )

现在这是使用伪随机数生成器要记住的事情。它们中的大多数旨在生成随机数而不是随机位。差异是微妙的。如果您需要 0 到 8 之间的数字,大多数程序员会说 rand()%8 这很糟糕,因为该算法用于随机化 32 位。但是您只使用了底部的 3 位。不好。这不会给你一个均匀的分布(假设这是你要找的)

您应该使用 8 * (rand() + 1) / (RAND_MAX) 现在会给您一个介于 0 和 8 之间的统一随机数。

现在使用硬件随机数生成器,您可能会产生随机位。如果确实如此,那么您将独立生成每个位。那么它更像是一组相同的独立随机位。这里的建模必须有点不同。请记住这一点,尤其是在模拟中,分布变得很重要。

于 2012-08-05T15:32:35.170 回答