多个随机数是相同的

可能重复:
随机数生成器仅生成一个随机数

一个初学者的问题。 我有一个非常简单的程序,它绘制一条线,我想随机化位置,但每次我创建一个新的Random实例时,它返回相同的值。 问题出在哪儿? 谢谢。

private void Draw() { Random random1 = new Random(); int randomNumber1 = random1.Next(0, 300); Random random2 = new Random(); int randomNumber2 = random2.Next(0, 300); Random random3 = new Random(); int randomNumber3 = random3.Next(0, 300); Random random4 = new Random(); int randomNumber4 = random4.Next(0, 300); System.Drawing.Graphics g = this.CreateGraphics(); Pen green = new Pen(Color.Green, 5); g.DrawLine(green, new Point(randomNumber1, randomNumber2), new Point(randomNumber3, randomNumber4)); } private void btndraw1_Click(object sender, EventArgs e) { Draw(); } 

发生这种情况的原因是,每次执行新的Random ,都会使用时钟进行初始化。 因此,在一个紧密循环(或许多一个接一个的调用)中,由于所有这些随机变量都使用相同的种子进行初始化,因此您可以获得相同的值很多次。

要解决此问题:只创建一个随机变量,最好在函数外部,并仅使用该实例。

 Random random1 = new Random(); private void Draw() { int randomNumber1 = random1.Next(0, 300); int randomNumber2 = random1.Next(0, 300); int randomNumber3 = random1.Next(0, 300); int randomNumber4 = random1.Next(0, 300); System.Drawing.Graphics g = this.CreateGraphics(); Pen green = new Pen(Color.Green, 5); g.DrawLine(green, new Point(randomNumber1, randomNumber2), new Point(randomNumber3, randomNumber4)); } 

只需使用相同的实例:

 Random random = new Random(); int randomNumber1 = random.Next(0, 300); int randomNumber2 = random.Next(0, 300); //... 

编程中的随机数并不是随机的; 它们基于一些独特的种子 ,它被采取和操纵以产生看似随机数的集合。 使用相同的种子将产生相同的数字集。

Random类的默认构造函数使用自系统作为种子启动以来经过的毫秒数,因此实际发生的是使用相同的种子。

实际上没有理由创建多个Random实例; 单个实例将在每次执行代码时生成随机数字集。

为了certificate我上面的默认种子声明,我使用了reflection:

 // System.Random /// Initializes a new instance of the  class, using a time-dependent default seed value. public Random() : this(Environment.TickCount) { } 

Environment.TickCount

 // System.Environment /// Gets the number of milliseconds elapsed since the system started. /// A 32-bit signed integer containing the amount of time in milliseconds that has passed since the last time the computer was started. /// 1 public static extern int TickCount { [SecuritySafeCritical] [MethodImpl(MethodImplOptions.InternalCall)] get; } 

您只需要一个Random类的一个实例。

 private void Draw() { Random random1 = new Random(); int randomNumber1 = random1.Next(0, 300); int randomNumber2 = random1.Next(0, 300); int randomNumber3 = random1.Next(0, 300); int randomNumber4 = random1.Next(0, 300); System.Drawing.Graphics g = this.CreateGraphics(); Pen green = new Pen(Color.Green, 5); g.DrawLine(green, new Point(randomNumber1, randomNumber2), new Point(randomNumber3, randomNumber4)); } private void btndraw1_Click(object sender, EventArgs e) { Draw(); } 
  private static readonly Random Random1 = new Random(); private void Draw() { int randomNumber1 = Random1.Next(0, 300); int randomNumber2 = Random1.Next(0, 300); int randomNumber3 = Random1.Next(0, 300); int randomNumber4 = Random1.Next(0, 300); System.Drawing.Graphics g = this.CreateGraphics(); Pen green = new Pen(Color.Green, 5); g.DrawLine(green, new Point(randomNumber1, randomNumber2), new Point(randomNumber3, randomNumber4)); } private void btndraw1_Click(object sender, EventArgs e) { Draw(); } 

您不应为每个数字创建新的Random对象。 相反,使用相同的对象:

 Random r = new Random(); private void Draw() { // Create 4 random numbers int[] numbers = Enumerable.Range(0, 4).Select(x => r.Next(0, 300)).ToArray(); System.Drawing.Graphics g = this.CreateGraphics(); Pen green = new Pen(Color.Green, 5); g.DrawLine(green, new Point(numbers[0], numbers[1]), new Point(numbers[2], numbers[3])); } 

随机数生成器(RNG)实际上不生成随机数。 相反,它使用算法来定义一系列数字,这些数字似乎是随机的。 此序列取决于在创建RNG时通过所述算法运行的seed

默认情况下,RNG是使用系统的时钟作为种子创建的,因为时钟通常会在程序运行时发生变化,因此很难预测“随机”序列。

在你的情况下,很可能,时钟在创建随机对象和另一个对象之间没有变化; 可能是由于CPU内部重新排序指令。

正如Blachshma所说,最好只创建一个随机对象并仅使用它。

 public static Random MyRNG = new Random(); // create a single static random object, that you can use across all classes private void Draw() { randomNumber1 = MyRNG.Next(0, 300); randomNumber2 = MyRNG.Next(0, 300); // and so forth } 

请记住, System.Random任何实例都不保证是线程安全的,这意味着如果您计划让多个线程共享同一个随机对象,则必须将其锁定。

 lock (MyRNG) { randomNumber = MyRNG.Next(0, 300); } 

如果不这样做可能会破坏您的随机对象,导致后续调用仅返回0。

.Net需要的随机类是种子值,您可以使用日期值作为种子,它可以工作。

 private void Draw() { Random random1 = new Random(unchecked((int)DateTime.Now.Ticks << (int)100)); int randomNumber1 = random1.Next(0, 300); Random random2 = new Random(unchecked((int)DateTime.Now.Ticks << (int)200)); int randomNumber2 = random2.Next(0, 300); Random random3 = new Random(unchecked((int)DateTime.Now.Ticks << (int)300)); int randomNumber3 = random3.Next(0, 300); Random random4 = new Random(unchecked((int)DateTime.Now.Ticks << (int)400)); int randomNumber4 = random4.Next(0, 300); System.Drawing.Graphics g = this.CreateGraphics(); Pen green = new Pen(Color.Green, 5); g.DrawLine(green, new Point(randomNumber1, randomNumber2), new Point(randomNumber3, randomNumber4)); } private void btndraw1_Click(object sender, EventArgs e) { Draw(); }