我有一个包含两个随机源的类。
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
是否正常?
答案 0 :(得分:10)
据我所知,标准做法是为随机数生成器播种一个不是由计算机计算的数字(但来自一些外部的,不可预测的来源)。这应该是你的rd()函数的情况。从那时起,您可以为您需要的每个伪随机数调用伪随机数生成器(PRNG)。
如果您担心数字不够随意,那么您应该选择不同的PRNG。熵是稀缺和宝贵的资源,应该这样对待。虽然,你现在可能不需要那么多随机数,但是你可能在将来;或其他应用程序可能需要它们。当应用程序要求时,您希望该熵可用。
听起来,对于您的应用,mersenne twister可以很好地满足您的需求。玩游戏的人不会觉得加载的团队不是随机的。
答案 1 :(得分:8)
如果您不使用它进行加密,那么重复使用由random_engine
播种的mt19937就可以了。
对于本答复的其余部分,我假设您在网络代码中使用随机数进行加密。 简而言之,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
答案 2 :(得分:7)
如果您需要模拟或游戏的随机性,那么您正在做的很好。只需调用随机设备一次,然后使用随机播种的伪RNG执行其他操作。作为奖励,您应该将种子值存储在日志文件中,以便以后可以重放伪随机序列:
auto const seed = std::random_device()();
// save "seed" to log file
std::mt19937 random_engine(seed);
(对于多个线程,使用主线程中的PRNG为生成的线程中的其他PRNG生成种子。)
如果你需要很多真正的随机性用于加密目的,那么PRNG永远不是一个好主意,因为长序列的输出包含的随机性比真正的随机性少得多,即你可以预测所有的随机性。小子集。如果您需要真正的随机性,您应该从一些不可预测的来源(例如热传感器,用户键盘/鼠标活动等)收集它。 Unix的/dev/random
可能是一个“真正的随机性”源,但它可能不会很快填满。
答案 3 :(得分:3)
您可能需要查看http://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful,了解您应该使用uniform_int_distribution的原因,以及random_device / mt19937的亲属优势。
在这段视频中,Stephan T. Lavavej明确指出,在visual C ++上,random_device可用于加密目的。
答案 4 :(得分:2)
答案取决于平台。我似乎记得在Visual C ++ 2010中,std :: random_device只是以某种无证方式播种的mt19937。
当然,您意识到任何基于随机数生成器的临时加密方案都可能非常弱。
答案 5 :(得分:-2)
假设这不是用于加密目的,关于随机数生成最重要的一点是要考虑你希望如何分配随机数以及你期望的范围是什么。
通常,库中的标准随机数生成器旨在提供均匀分布。所以数字的范围在0到一些RAND_MAX之间(比如在32位机器上它是2 ^ 31 -1)
现在,这是伪随机数生成器要记住的事情。它们中的大多数被设计为生成随机数而不是随机位。差异很微妙。如果你需要0到8之间的数字,大多数程序员会说rand()%8 这很糟糕,因为该算法用于随机化32位。但是你只使用底部的3位。不好。这不会给你一个统一的分布(假设你正在寻找)
你应该使用8 *(rand()+ 1)/(RAND_MAX),它现在会给你一个0到8之间的均匀随机数。
现在使用硬件随机数生成器,您可能会生成随机位。如果确实如此,则每个位都独立生成。然后它更像是一组相同的独立随机位。这里的建模必须有点不同。记住这一点,特别是在模拟中,分布变得很重要。