C++ 我应该使用从std::random_设备中播种的随机引擎,还是每次都使用std::random_设备

C++ 我应该使用从std::random_设备中播种的随机引擎,还是每次都使用std::random_设备,c++,random,c++11,C++,Random,C++11,我有一个类,它包含两个随机性来源 std::random_device rd; std::mt19937 random_engine; 我通过调用std::random_device为std::mt19937播种。如果我想生成一个数字而不关心重复性,我应该调用rd()还是random_engine() 在我的特殊情况下,我确信这两种方法都可以很好地工作,因为这将在一些网络代码中调用,在这些代码中,性能不是很高,结果也不是特别敏感。然而,我对何时使用硬件熵和何时使用伪随机数的一些“经验法则”感兴

我有一个类,它包含两个随机性来源

std::random_device rd;
std::mt19937 random_engine;
我通过调用
std::random_device
std::mt19937
播种。如果我想生成一个数字而不关心重复性,我应该调用
rd()
还是
random_engine()

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

目前,我只使用
std::random_device
为我的
std::mt19937
引擎进行种子设定,并且我使用
std::mt19937
引擎生成程序所需的任何随机数

编辑:以下是我使用此特定示例的确切解释:

这是一个游戏程序。这个特殊的游戏允许用户在开始一轮对抗对手之前定制他们的“团队”。建立战斗的一部分包括向服务器发送团队。我的程序有几个团队,并使用随机数来确定加载哪个团队。每一场新的战斗都会调用std::random_设备,为伪随机数生成器植入种子。我记录战斗的初始状态,其中包括我随机选择的团队和初始种子


我在这个问题中所问的特定随机数是针对随机团队选择的(不让对手提前知道我使用的团队是有益的,但不是关键任务),但我真正想要的是经验法则。如果我不需要重复我的数字,那么总是使用
std::random\u设备可以吗?或者说,使用熵的速度比收集熵的速度快是真的有风险吗?

如果你不使用它进行加密,那么重复使用由
random\u引擎播种的mt19937就可以了

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

随着时间的推移,您可能会(可能是间接地)泄漏信息,因此攻击者可能会开始预测随机数。至少在理论上是这样,但事实就是这样。来自维基百科

…因为此图是来自
生成哪些未来迭代)允许预测所有未来迭代

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


这里提供了各种示例(带代码)

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

auto const seed = std::random_device()();
// save "seed" to log file
std::mt19937 random_engine(seed);
(对于多个线程,使用主线程中的PRNG为派生线程中的其他PRNG生成种子。)


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

假设这不是出于加密目的,关于随机数生成,最重要的一点是要记住您希望随机数的分布如何,以及您期望的范围是什么

通常,库中的标准随机数生成器设计为均匀分布。因此,数字的范围将在0和一些RAND_MAX之间(比如在32位机器上是2^31-1)

下面是伪随机数生成器要记住的事情。它们中的大多数设计用于生成随机数,而不是随机位。差别是微妙的。如果需要介于0和8之间的数字,大多数程序员会说rand()%8 这是不好的,因为该算法是用于随机化32位的。但您只使用了底部的3位。无益。这不会给您一个统一的分布(假设这是您正在寻找的)

您应该使用8*(rand()+1)/(rand_MAX),它现在将为您提供一个介于0和8之间的统一随机数


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

答案取决于平台。我似乎记得,用VisualC++ 2010,STD::RealthyDebug只是MT1937以一些未文档化的方式播种。


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

据我所知,标准做法是使用计算机无法计算的数字(但来自某些外部、不可预测的源)为随机数生成器添加种子。rd()函数就是这样。从那时起,您需要为每个伪随机数调用伪随机数生成器(PRNG)

如果你担心这些数字不是随机的