每次运行应用程序时,随机数生成器生成相同的数字

时间:2014-03-28 12:10:03

标签: c# .net random

我知道这个问题已多次提出,但这些解决方案都不适用于我。

首先,我在名为RandomNumGenerator(items)

的方法中执行了此操作
List<int> randNum = new List<int>();
foreach (var item in items)
{
    randNum.Add(new Random(1000).Next());
}

这总是给了我相同的数字,然后在看this answer之后我做了这个:

Random rnd = new Random(1000);
foreach (var item in items)
{
    randNum.Add(rnd.Next());
}

这给了我以下数字

325467165 
506683626   
1623525913  
2344573     
1485571032

现在虽然循环的每次迭代都没问题,但问题是,当我停止并重新运行应用程序时,我得到了我之前重新获得的相同数字。

325467165 
506683626   
1623525913  
2344573     
1485571032

仅在调试期间出现这种情况,或者每次拨打RandomNumGenerator时都会遇到同样的问题吗?

6 个答案:

答案 0 :(得分:155)

您总是使用相同的种子1000在Random实例播种:

Random rnd = new Random(1000);

这不会那样做,因为当前时间用作种子:

Random rnd = new Random();

查看int的{​​{3}}。

  

为不同的Random对象提供相同的种子值   每个实例产生相同序列的随机数。

答案 1 :(得分:41)

根据MSDN

public Random(
    int Seed
)
  

种子

     

用于计算伪随机数序列的起始值的数字。如果指定了负数,则使用该数字的绝对值。

大多数初学者涉及RNG(随机数发生器)的错误的原因是缺乏对种子&#34;种子的理解。是和它的作用。


那么 a&#34;种子&#34;?

Random类是用于生成伪随机数的类 - 或出现的数字是随机的。它们通常是一个数学函数,它使用一个参数 - &#34;种子&#34; - 生成一系列似乎是随机的数字。

new Random(1000)的情况下,前5个非负随机整数是

  

325467165
  506683626
  1623525913个
  2344573个
  1485571032

在你的第一个代码中,每次需要一个随机数时,你都会用相同的种子创建一个新的伪随机数序列,所以显然你的数组用相同的数字填充:{{ 1}},恰好是由325467165生成的第一个非负整数。

这也解释了为什么每次启动应用程序时,第二个代码总是生成相同的伪随机数序列。

为确保您的应用始终生成不同的伪随机序列,您每次都需要使用不同的种子。到目前为止,确保 的最简单方法是花费你的时间,字面意思。

new Random(1000)

幸运的是,你不必输入这么多,因为default constructor for the Random class已经做了类似的事情。

Random rnd = new Random(DateTime.UtcNow.Millisecond);
// Taking the millisecond component, because it changes quickly

请注意,Random rnd = new Random(); // Much simpler, isn't it? 线程安全;如果多个线程同时尝试访问同一个Random对象,则RNG将在其生命周期的剩余时间内仅返回0。

另外需要注意的是,一个接一个地创建多个Random对象 - 即使使用时间作为种子 - 也可能导致相同的伪随机数序列。

Random

在上面的代码中,非常高Random r1 = new Random(); Random r2 = new Random(); Random r3 = new Random(); Random r4 = new Random(); r1r2r3都会生成相同的序列

怎么可能?
好吧,(联合国)幸运的是,CPU正在快速发展。 1 GHz CPU每秒可执行大约10亿条指令(给予或接受);这是每1纳秒的1条指令 - 或者每1 百万分之一的指令毫秒。
创建一个新的r4对象可能需要相当多的指令,但绝对少于而不是百万个。


那么为什么我们需要手动定义种子,如果使用时钟的当前毫秒数是我们所有的&#34;想要并且已经是默认值?

因为它对于保持多个终端同步非常有用。

想象一下游戏中随机出现的重要现象,例如可能完全颠覆游戏的天气变化。你不希望只有一方遭受大雾,其余的仍然是晴朗的天气,对吗?

当然,您可以让服务器或主机生成随机天气变化并通知玩家;或者您可以在游戏开始之前定义种子,并使用该种子来确保相同的随机性&#34;在整个游戏过程中所有玩家。

不编码很有趣吗?

答案 2 :(得分:19)

你需要改变这个:

Random rnd = new Random(1000);

Random rnd = new Random();

来自Random Constructor docs

  

默认种子值是从系统时钟派生的,并且是有限的   解析度。结果,创建了不同的Random对象   通过调用默认构造函数来关闭连续   相同的默认种子值,因此,将产生相同的   随机数集。使用单个可以避免此问题   随机对象生成所有随机数。你也可以解决   它通过修改系统时钟返回的种子值然后   明确地向Random(Int32)提供这个新的种子值   构造函数。有关更多信息,请参阅Random(Int32)构造函数。

答案 3 :(得分:5)

关键概念是随机种子 - 随机派生其他所有内容的初始数据。如果种子是相同的,那么“随机”序列将是相同的。

默认情况下,种子设置为零,这显然会导致程序运行中重复序列。

为了避免这种情况,你可以像这样构建你的随机:

Random rnd = new Random();

......在引擎盖下,是:

Random rnd = new Random(Environment.TickCount);

这将从OS启动开始以毫秒为单位初始化Random对象。每次程序启动时都会有所不同,因此每次都会得到不同的随机序列。

答案 4 :(得分:2)

Random .Next()方法生成伪随机数。您应该声明并初始化随机对象,而不是每次都创建新对象。并且不需要使用任何Cryctography .. :)

答案 5 :(得分:-1)

您应该使用班级随机变量。如果您在方法级别使用新的Random作为本地,则依赖于时间的种子将重复生成相同的随机数序列。

class Program
{
 static Random _r = new Random();
 static void Main()
 {
// use _r variable to generate random number
 }
}