我只是想知道在程序开始时只能将随机数生成器播种一次是否足够。我编写使用随机数的函数。我从不在函数中播放rand()生成器,而是在主条目上调用srand()。例如。我的程序可能看起来像:
void func1()
{
std::cout << "This is func1 " << std::rand() << std::endl;
}
void func2()
{
std::cout << "This is func2 " << std::rand() << std::endl;
}
int main()
{
std::srand(std::time(NULL));
func1();
func2();
return 0;
}
通过这样做,我可以轻松地从主条目关闭播种。它在调试程序时很有用 - 每次运行程序时结果都保持不变,没有播种。有时,如果由于某个随机数而出现问题,如果要生成一组不同的随机数,它可能会消失,所以我更喜欢这种简单的机制来关闭播种。
但是,我注意到在C ++ 11的新随机效用集中,随机数生成器必须在使用之前进行实例化。 (例如default_random_engine)。每次发电机必须单独播种。我想知道是否真的鼓励在需要新发电机时重新启动发电机。我知道我可以像以前一样创建一个全局随机生成器并只播种一次,但我真的不喜欢使用全局变量的想法。否则,如果我创建一个本地随机数生成器,我就会失去全局关闭种子以进行调试或其他任何目的的能力。
我很高兴能够学习C ++ 11中的新功能,但有时它会让人感到非常困惑。如果我对新的随机发生器有任何问题,有人能告诉我吗?或者什么可能是C ++ 11中的最佳实践?
答案 0 :(得分:17)
这肯定取决于您正在开发的系统的总体目标,但一般情况下,您只需要在初始化该系统时为任何需要随机数生成器(RNG)的系统播种。
在游戏开发中,每个系统(AI,程序内容生成器,粒子等)都有一个单独的RNG来隔离该系统以进行调试和维护。
如果存储种子,您还可以使用非常少的数据重放逻辑(仅需要来自每个帧的增量输入)。这不仅可以让您更轻松地调试应用程序,还可以支持为用户提供录制和重放功能。显然,如果您正在创建重播模式,则需要在每次重播会话之前为每个系统提供系统记录的种子。
还有其他系统,如密码学,您可能需要定期建立新种子。您可能希望随着时间的推移使种子过期,或者需要在与客户端应用程序的每次握手时生成新的种子。但是,您可能希望使用加密库,因为它们可能会比您自己创建的更强大。
答案 1 :(得分:7)
具有随机数生成器(RNG)需要实例化的原因之一是它可以将其状态保持在内部,这样在多线程应用程序中,当多个线程使用相同的线程时,您不会引入非确定性RNG具有流程全局状态。假设您有两个线程,每个线程处理一个问题的独立部分 - 如果状态(种子)是RNG实例的私有,那么当您使用已知值为每个线程的RNG设定种子时,您可以具有确定性。另一方面,如果RNG将状态保持在全局变量中,则每个线程观察到的随机数序列取决于它们对RNG的调用的中断 - 您现在已经引入了非确定性。
用于在多线程应用程序中分配工作的一种编程模式是thread pool。如果为要执行的池中的工作线程排队的工作项需要RNG,并且您希望执行从运行到运行具有确定性,那么您希望每个线程在从中拉出新工作项后重新设置RNG的种子。队列
以下是处理此问题的问题:Deterministic random number generator tied to instance (thread independent)
在单线程应用程序中,没有必要重新种子RNG,事实上它是不受欢迎的,因为通过这样做,你可以在它开始重复之前缩短它的周期。例外情况是@MatthewSanders指出的,密码学 - 在这种情况下,你需要最大熵(最小确定性),因为随机数被用作私钥。