"Resetting"多次伪随机数生成器种子?



今天,我的朋友有一个想法,使用生成的伪随机数多次设置伪随机数生成器的种子,以"使事情更加随机"。

C#中的一个例子:

// Initiate one with a time-based seed
Random rand = new Random(milliseconds_since_unix_epoch());
// Then loop for a_number_of_times...
for (int i = 0; i < a_number_of_times; i++)
{
// ... to initiate with the next random number generated
rand = new Random(rand.Next());
}
// So is `rand` now really random?
assert(rand.Next() is really_random);

但我在想,这可能会增加获得用于伪随机数生成器的重复种子的机会。

这个

  1. 使事情更加随机
  2. 使其循环通过所使用的一定数量的种子,或者
  3. 对随机性没有任何影响(即既不增加也不减少)

伪随机数生成器方面的专家能给出一些详细的解释吗?这样我就可以说服我的朋友了?我很乐意看到在一些伪随机数生成器算法中解释更多细节的答案。

伪随机数有三个基本的使用级别。每个级别都包含其下的级别。

  1. 没有特定相关性保证的意外数字。这个级别的生成器通常有一些隐藏的相关性,这些相关性可能对您很重要,也可能不重要
  2. 具有已知非相关性的统计独立数。这些通常是数值模拟所必需的
  3. 无法猜测的加密安全数字。当安全性有问题时,这些总是必需的

每一个都是确定性的。随机数生成器是一种具有某种内部状态的算法。应用该算法一次会产生一个新的内部状态和一个输出数。为发电机播种意味着建立一个内部状态;种子接口并不总是允许设置所有可能的内部状态。作为一个很好的经验法则,总是假设默认库random()例程只在最弱的级别1运行。

为了回答你的具体问题,问题(1)中的算法不能增加随机性,(2)可能会减少随机性。因此,对随机性的期望值严格低于一开始就播种一次。原因来自于短迭代循环的可能存在。函数F的迭代循环是一对整数nk,其中F^(n) (k) = k,其中指数是应用F的次数。例如,F^(3) (x) = F(F(F(x)))。如果有一个短的迭代周期,随机数会比其他情况下更频繁地重复。在给出的代码中,迭代函数是为生成器播种,然后获得第一个输出。

为了回答一个你没有问到的问题,但这与理解这一点有关,用毫秒计数器播种会使你的生成器无法通过3级测试,不可测试。这是因为可能的毫秒数在密码上很小,这是一个已知需要进行彻底搜索的数字。截至本文撰写之时,2^50应被视为密码较小。(对于任何一年的加密量,请找一位声誉良好的专家。)现在一个世纪的毫秒数约为2^(41.5),所以出于安全目的,不要依赖这种形式的种子。

您的示例不会增加随机性,因为熵没有增加。它只是从程序的执行时间派生出来的。

计算机不是使用基于当前时间的东西,而是维护一个熵池,并用统计上随机的(或者至少是不可预测的)数据来构建它。例如,网络数据包之间的定时延迟,或按键,或硬盘驱动器读取时间。

如果你想要好的随机数,你应该利用熵池。这些被称为加密安全伪随机数生成器

在C#中,有关获取安全随机数的正确方法,请参阅Cryptography.RandomNumberGenerator类

这不会让事情变得更"随机"。

我们的种子决定了rand.next()给我们的随机但完全确定的数字序列。

您的代码没有使事情变得更随机,而是定义了从初始种子到某个最终种子的映射,并且,给定相同的初始种子,您最终总是得到相同的最终种子。

试着玩这个代码,你会明白我的意思(还有,这里有一个链接到你可以在浏览器中运行的版本):

int my_seed = 100; // change my seed to whatever you want
Random rand = new Random(my_seed);
for (int i = 0; i < a_number_of_times; i++)
{
rand = new Random(rand.Next());
}
// does this print the same number every run if we don't change the starting seed?
Console.WriteLine(rand.Next()); // yes, it does

具有此最终种子的"随机"对象与任何其他"随机"物体一样。它只是花了你更多的时间来创建它。

最新更新