1) 创建具有不同种子的同一随机数生成器的多个实例并在程序的不同部分使用这些随机数生成器是否是个好主意?
没有。一般不推荐上述方案。
在他的著作《计算机编程艺术,第 2 卷:半数值算法》中。 Addison-Wesley,Reading,MA,第三版,1997,Knuth 博士指出
发明一个万无一失的随机数来源并不容易。
在这种情况下,我指出从随机序列中获取子序列的随机性可能比原始随机数序列的随机性小:
请注意,Micosoft 的 Random 实现基于减法滞后斐波那契生成器:
这种随机数生成器以内置的三点相关性而闻名,毕竟,我们正在生成下一个随机数:
这些类型的随机数生成器还严重依赖于初始 55 数字状态的初始化。糟糕的初始化可能会导致糟糕的随机数。在上述情况下,类似的状态可能会导致来自不同随机数生成器中的每一个的相关随机数。微软甚至在他们关于 System.Random 的 MSDN 帖子中建议不要这样做:MSDN The System.Random class and thread safety:
我们建议您创建单个 Random 实例来生成应用所需的所有随机数,而不是实例化单个 Random 对象。
我们将看一个示例,其中特定的初始化会在不同的随机数生成器之间产生强相关性并寻找替代方案。
2) 我已经实现了一个程序,该程序尝试如上所述初始化 64 个 Random 实例,以便我们观察任何可见的缺陷。我选择了一个特定的初始化作为概念证明:
int size = 64; // The number of random numbers generators
int length = 20; // The number of random numbers from each generator
int steps = 18; // Move 18 steps forward in the beginning to show a particular phenomenon
Random[] r = new Random[size];
for (int i = 0; i < size; i++)
{
r[i] = new Random(i + 1);
// move RNG forward 18 steps
for (int j = 0; j < steps; j++)
{
r[i].Next(3);
}
}
for (int i = 0; i < size; i++)
{
for (int j = 0; j < length; j++)
{
Console.Write(r[i].Next(3) + ", "); // Generate a random number, 0 represents a small number, 1 a medium number and 2 a large number
}
Console.WriteLine();
}
这个程序生成这里显示的输出,每一行代表另一个RNG的输出:
请注意突出显示的列:在特定位置,RNG 似乎同步并产生看起来并不相互独立的输出。
我还想补充一点,创建一个随机数列表并从每一行的列表中获取一个随机数也会产生看起来很差的随机数(已知这里使用的 RNG 在某些统计数据之后失败)全部!)。
3) 使用的 RNG 类型取决于您的上下文。有些人可能对上述输出感到满意。在其他情况下,所使用的 RNG 可能无法使用(蒙特卡洛模拟和密码学是两种情况,其中 System.Random 应该从不使用,即使对于一个随机数流也是如此)。
如果您需要提取随机数的多个子序列,请查找专为此目的设计的 RNG:
4) 最后,如果我想在多个线程中使用 System.Random 怎么办?
Microsoft MSDN 在我上面提到的同一个链接中有答案: