Почему кажется, что мой генератор случайных чисел не случайный в C #? - PullRequest
19 голосов
/ 31 мая 2009

Я работаю в Microsoft Visual C # 2008 Express.

Я нашел этот фрагмент кода:

    public static int RandomNumber(int min, int max)
    {
        Random random = new Random();

        return random.Next(min, max);
    }

проблема в том, что я запускал его более 100 раз, и он ВСЕГДА дает мне один и тот же ответ, когда мои min = 0 и max = 1. Я получаю 0 каждый раз. (Я создал тестовую функцию для ее запуска - действительно - я получаю 0 каждый раз). Мне трудно поверить, что это совпадение ... Есть ли что-то еще, что я могу сделать, чтобы проверить или проверить это? (Я перезапустил тест с min = 0 и max = 10 и первые 50 раз, результат всегда был «5», 2-й раз 50 раз, результат всегда был «9».

?? Мне нужно что-то более последовательное, случайное ...

-Adeena

Ответы [ 13 ]

47 голосов
/ 31 мая 2009

Проблема с min = 0 и max = 1 состоит в том, что min включительно, а max эксклюзивно. Таким образом, единственное возможное значение для этой комбинации - 0.

32 голосов
/ 31 мая 2009
random = new Random();

Инициирует генератор случайных чисел с текущим временем (в секундах). Когда вы вызываете свою функцию много раз до изменения системных часов, генератор случайных чисел запускается с тем же значением, поэтому он возвращает ту же последовательность значений.

18 голосов
/ 31 мая 2009

Не создавайте метод-обертку для Next. Это тратит впустую циклы, создавая новый экземпляр класса Random. Просто используйте тот же!

Random myRand = new Random();

for(int i = 0; i < 10; i++)
{
    Console.WriteLine(myRand.Next(0, 10).ToString());
}

Это должно дать вам десять случайных значений.

Как уже было сказано - Random - это псевдослучайный (как и все реализации), и если вы создадите 100 экземпляров с одинаковым начальным числом, вы получите 100 экземпляров с одинаковыми результатами. Убедитесь, что вы повторно используете класс.

Кроме того, как говорили люди, имейте в виду, что MinValue является эксклюзивным, а MaxValue - эксклюзивным. Для чего вы хотите, сделайте myRand.Next (0, 2).

7 голосов
/ 31 мая 2009

Эта перегрузка Next () возвращает:

32-разрядное целое число со знаком, большее или равное minValue и меньшее, чем maxValue; то есть диапазон возвращаемых значений включает minValue, но не MaxValue. Если minValue равно maxValue, возвращается minValue.

0 - единственное возможное значение для возврата. Возможно, вы хотите random.NextDouble (), который будет возвращать двойное значение от 0 до 1.

6 голосов
/ 31 мая 2009

Вы всегда получаете 0, потому что Random.Next возвращает целые числа. Вам нужно позвонить Random.NextDouble, который вернет число от 0 до 1. Кроме того, вы должны повторно использовать ваш случайный экземпляр, например:

[ThreadStatic]
static Random random;
public static Random Random { 
    get {
        if (random == null) random = new Random();
        return random;
    }
}
public static int RandomInteger(int min, int max)
{
    return Random.Next(min, max);
}
public static double RandomDouble() //Between 0 and 1
{ 
    return Random.NextDouble();
} 

Если вы хотите криптографически защищенные случайные числа, используйте класс RNGCryptoServiceProvider; см. эту статью

РЕДАКТИРОВАТЬ: поток безопасности

6 голосов
/ 31 мая 2009

Минус включительно, но максимум эксклюзив. Проверьте API

3 голосов
/ 31 мая 2009

Помимо проблемы 0-1, уже отмеченной в других ответах, ваша проблема является реальной, когда вы ищете диапазон 0-10 и получаете идентичные результаты 50 раз подряд.

new Random() должен возвращать случайное число с начальным числом, инициализированным из таймера (текущая секунда), но, очевидно, вы вызываете этот код 50 раз в секунду. MSDN предлагает: «Чтобы повысить производительность, создайте один случайный случай, чтобы генерировать много случайных чисел во времени, вместо того, чтобы многократно создавать новый случайный случай, чтобы генерировать одно случайное число». Если вы создадите генератор случайных чисел один раз за пределами метода, это должно устранить проблему «неслучайности», а также повысить производительность.

Также рассмотрите этот пост для лучшего генератора псевдослучайных чисел, чем системный, если вам нужны псевдослучайные числа "более высокого качества".

1 голос
/ 25 ноября 2017

Вы неправильно понимаете строку "random.Next (min, max)". «min» - место наименьшего числа, которое может быть сгенерировано случайным образом. В то время как «max» находится на месте самого низкого числа, которое НЕ может быть сгенерировано, оно не находится на месте самого большого числа, которое может быть получено. Поэтому, когда линия случайна. Далее (0, 1) вы в основном позволяете рисовать только 0.

1 голос
/ 31 мая 2009

Это дополнение к любым ответам, поскольку ответом на этот конкретный вопрос является то, что границы должны быть (0, 2), а не (0, 1).

Однако, если вы хотите использовать метод статической обертки, вы должны помнить, что Random не является поточно-ориентированным, поэтому вам нужно либо предоставить собственный механизм синхронизации, либо предоставить экземпляр для каждого потока. Вот в значительной степени неблокирующая реализация, которая использует один генератор для заполнения каждого генератора на поток:

public static class ThreadSafeRandom
{
    private static readonly Random seed = new Random();

    [ThreadStatic]
    private static Random random;

    public static int Next(int min, int max)
    {
        if (random == null)
        {
            lock (seed)
            {
                random = new Random(seed.Next());
            }
        }

        return random.Next(min, max);
    }

    // etc. for other members
}
1 голос
/ 31 мая 2009

Как уже упоминали другие, случайный объект, создаваемый несколько раз в секунду, использует ту же секунду, что и начальное число, поэтому я бы поместил конструктор Random за пределы цикла и передал его в качестве параметра, например:

public static int RandomNumber(Random random, int min, int max)
{
    return random.Next(min, max);
}

Также, как упоминалось другими, максимальное значение является эксклюзивным, поэтому, если вы хотите 0 или 1, вы должны использовать [0,2] в качестве [минимального, максимального] или некоторого большего максимального значения, а затем выполнить двоичное И с 1.

public static int RandomOneOrZero(Random random)
{
    return random.Next(0, int.MaxValue) & 1;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...