Multiple random numbers are the same [duplicate]

2019-01-09 11:38发布

Possible Duplicate:
Random number generator only generating one random number

A beginner question. I have a very simple program that draws a line and I want to randomize the locations, but each time I create a new instance of Random it returns the same value. Where is the problem? Thank you.

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();
}

标签: c# random
7条回答
地球回转人心会变
2楼-- · 2019-01-09 12:05

What random class of .Net needs is a seed value you can use a date value as a seed and it would work.

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();
}
查看更多
时光不老,我们不散
3楼-- · 2019-01-09 12:06

A random number generator (RNG) does not actually generate random numbers. Instead, it uses an algorithm to define a sequence of numbers, that appear to be random. This sequence depends on the seed that is run through said algorithm at the time you RNG is created.

By default, RNGs are created using the system's clock as a seed, since the clock will usually vary every time the program is run, making it extremely difficult to predict the "random" sequence.

In your case, it is very likely, that the clock didn't change between creating a random object and another; possibly due to CPU-internal re-ordering of instructions.

As Blachshma states, it is best to create only a single random object and use only that.

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
}

Keep in mind that any instance of System.Random are not guaranteed to be thread-safe, meaning that if you plan on having multiple threads share the same random object, you must lock it.

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

Failure to do so might break your random object, leading to consequent calls returning only 0 as a result.

查看更多
来,给爷笑一个
4楼-- · 2019-01-09 12:09
    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();
    }
查看更多
等我变得足够好
5楼-- · 2019-01-09 12:13

You shouldn't create a new Random object for each number. Instead, use the same object:

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]));
}
查看更多
【Aperson】
6楼-- · 2019-01-09 12:18

The reason this happens is that every time you do a new Random it is initialized using the clock. So in a tight loop (or many calls one after the other) you get the same value lots of times since all those random variables are initialized with the same seed.

To solve this: Create only one Random variable, preferably outside your function and use only that one instance.

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));
}
查看更多
▲ chillily
7楼-- · 2019-01-09 12:26

Simply use the same instance:

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

Random numbers in programming are not really random; they are based on some unique seed that is taken and manipulated to generate what appears to be set of random numbers. Using the same seed will result in same set of numbers.

The default constructor of the Random class is using the number of milliseconds elapsed since the system started as the seed, so what actually happened is the same seed was used.

There is really no reason to create more than once Random instance; the single instance will generate random set of numbers on each execution of the code.

To prove my above statement of default seed, I used reflection:

// 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)
{
}

And the 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;
}
查看更多
登录 后发表回答