我最近在另一篇文章的评论中讨论了相同类型的多个随机数生成器的初始化,在讨论中我们提出了以下问题:
1)使用不同的种子创建相同随机数生成器的多个实例并在程序的不同部分使用这些随机数生成器是一个好主意吗?
2)特别是,使用.Net Random类创建随机数生成器的技术,如下所示,并在不同的程序上下文中使用每个RNG会导致问题:
int size = 64; // The number of RNGs to use
int seed; // Get seed using some normal technique
Random[] r = new Random[size];
for (int i = 0; i < size; i++)
{
r[i] = new Random(seed + i);
}
3)如果需要多个随机数流,你会建议什么?
4)如果需要线程安全性,您会建议如何生成随机数?
答案 0 :(得分:11)
1)使用不同的种子创建相同随机数生成器的多个实例并在程序的不同部分使用这些随机数生成器是一个好主意吗?
没有。一般不推荐上述方案。
在他的着作“计算机程序设计的艺术”第2卷:研究数学算法中。 Addison-Wesley,Reading,MA,第三版,1997年,Knuth博士表示
发明一个万无一失的随机数源并不容易。
在这种情况下,我指出从随机序列中获取子序列可能比原始随机数序列更不随机:
请注意,Micosoft的Random实现基于一个subractive-lagged-fibonacci生成器:
这种随机数生成器以内置三点相关性着称,毕竟我们生成下一个随机数:
这些随机数生成器也在很大程度上依赖于其初始55数字状态的初始化。初始化不佳可能导致随机数较差。在上述情况下,类似的状态可能导致来自每个不同随机数发生器的相关随机数。 Microsoft甚至建议在他们关于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在我上面提到的相同链接中有答案:
答案 1 :(得分:1)
不确定“多个随机数流”是什么意思。在随机数中,任意两个随机数之间没有关系,没有顺序,每个都是一个独立的实例。
如果您使用加密PRNG,则无需播种。考虑.net RNGCryptoServiceProvider Class。