Почему кажется, что мой генератор случайных чисел не является случайным в С#?

Я работаю в Microsoft Visual С# 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", второй - 50 раз, результат всегда был "9".

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

-Adeena

Ответы

Ответ 1

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

Ответ 2

random = new Random();

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

Ответ 3

Не создавайте метод wrapper для 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).

Ответ 4

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

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

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

Ответ 5

Минус включен, но max является исключительным. Проверьте API

Ответ 6

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

[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; см. в этой статье

EDIT: безопасность потока

Ответ 7

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

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

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

Ответ 8

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

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

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

public static int RandomOneOrZero(Random random)
{
    return random.Next(0, int.MaxValue) & 1;
}

Ответ 9

Это добавление к любым ответам, так как ответ на этот конкретный вопрос должен быть равен (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
}

Ответ 10

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

Ответ 11

Несколько плакатов заявили, что Random() использует семя, основанное на текущей секунде на системных часах, и любой другой экземпляр Random, созданный в той же секунде, будет иметь одно и то же семя. Это неверно. Семя для беззаметного конструктора Random основано на количестве тиков или количестве миллисекунд с момента загрузки. Это значение обновляется в большинстве систем примерно каждые 15 миллисекунд, но оно может меняться в зависимости от аппаратных и системных настроек.

Ответ 12

Я нашел очень простой, но эффективный способ генерации случайных чисел, просто взяв последние две цифры текущего времени в миллисекундах:

   int seed = Convert.ToInt32(DateTime.Now.Millisecond.ToString().Substring(1, 2));
   int cnr = new Random(seed).Next(100);

Это грубо, но это работает!:-)

Конечно, он статистически генерирует одинаковое число каждые сто раз. В качестве альтернативы вы можете взять все три цифры или объединить с другими значениями datetime, например, секунд или около того.

Ответ 13

в VB я всегда начинается с функции Randomize(). Просто вызовите Randomize(), затем запустите свою случайную функцию. Я также делаю следующее:

Function RandomInt(ByVal lower As Integer, ByVal upper As Integer) As Integer
    Return CInt(Int((upper - lower + 1) * Rnd() + lower))
End Function

Надеюсь, это поможет!:)