Подтвердить что ты не робот

Несколько случайных чисел одинаковы

Возможный дубликат:
Генератор случайных чисел генерирует только одно случайное число

Начальный вопрос. У меня очень простая программа, которая рисует строку, и я хочу рандомизировать местоположения, но каждый раз, когда я создаю новый экземпляр 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();
}
4b9b3361

Ответ 1

Причина этого в том, что каждый раз, когда вы делаете новый 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));
}

Ответ 2

Просто используйте один и тот же экземпляр:

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

Ответ 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();
    }

Ответ 4

    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

Вам не следует создавать новый объект 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]));
}

Ответ 6

Генератор случайных чисел (RNG) фактически не генерирует случайные числа. Вместо этого он использует алгоритм для определения последовательности чисел, которые кажутся случайными. Эта последовательность зависит от seed, которая выполняется через указанный алгоритм в момент создания RNG.

По умолчанию RNG создаются с использованием системных часов в качестве семени, так как часы обычно будут меняться каждый раз, когда программа запускается, что чрезвычайно затрудняет предсказание "случайной" последовательности.

В вашем случае очень вероятно, что часы не изменились между созданием случайного объекта и другим; возможно, из-за внутреннего переупорядочения инструкций CPU.

Как утверждает Блачшма, лучше всего создать только один случайный объект и использовать только это.

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.

Ответ 7

Какой случайный класс .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();
}