可能重复:
Random number generator only generating one random number
初学者问题。我有一个非常简单的程序,它绘制一条线,我想随机化位置,但每次我创建一个新的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();
}
答案 0 :(得分:54)
发生这种情况的原因是,每次执行新的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));
}
答案 1 :(得分:10)
只需使用相同的实例:
Random random = new Random();
int randomNumber1 = random.Next(0, 300);
int randomNumber2 = random.Next(0, 300);
//...
编程中的随机数并不是随机的;它们基于一些独特的种子,它被采取和操纵以生成看似随机数的集合。使用相同的种子将产生相同的数字集。
Random
类的默认构造函数使用自系统作为种子启动以来经过的毫秒数,因此实际发生的是使用相同的种子。
实际上没有理由创建多个Random
实例;单个实例将在每次执行代码时生成随机数字集。
为了证明我上面的默认种子声明,我使用了反射:
// System.Random
/// <summary>Initializes a new instance of the <see cref="T:System.Random" /> class, using a time-dependent default seed value.</summary>
public Random() : this(Environment.TickCount)
{
}
Environment.TickCount
:
// System.Environment
/// <summary>Gets the number of milliseconds elapsed since the system started.</summary>
/// <returns>A 32-bit signed integer containing the amount of time in milliseconds that has passed since the last time the computer was started.</returns>
/// <filterpriority>1</filterpriority>
public static extern int TickCount
{
[SecuritySafeCritical]
[MethodImpl(MethodImplOptions.InternalCall)]
get;
}
答案 2 :(得分:3)
您只需要一个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();
}
答案 3 :(得分:3)
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();
}
答案 4 :(得分:3)
您不应为每个号码创建新的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]));
}
答案 5 :(得分: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。
答案 6 :(得分:-4)
.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();
}