Rand () работает некорректно

Возможный дубликат:
Почему я всегда получаю одну и ту же последовательность случайных чисел с помощью rand ()?

Я экспериментировал с генерацией случайных чисел на C и наткнулся на кое-что странное. Я не знаю, есть ли это только в моем компиляторе, но всякий раз, когда я пытаюсь сгенерировать псевдослучайное число с помощью функции rand (), он возвращает очень предсказуемое число - число, сгенерированное с параметром до плюс 3,125, чтобы быть точным. Это сложно объяснить, но вот пример.

srand(71);
int number = rand();
printf("%d", number);

Это возвращает 270.

srand(72);
int number = rand();
printf("%d", number);

Это возвращает 273.

srand(73);
int number = rand();
printf("%d", number);

Это возвращает 277.

srand(74);
int number = rand();
printf("%d", number);

Это возвращает 280.

Каждое восьмое число на 4 выше. В противном случае это 3.

Это не может быть правдой. Что-то не так с моим компилятором?

Изменить: я понял это - я создал функцию, в которой я заполняю только один раз, затем я зацикливаю rand(), и он генерирует случайные числа. Спасибо вам всем!


person user1676037    schedule 17.09.2012    source источник
comment
Единственное, что здесь не так, это ваше понимание раздачи. Посейте один раз, и не более того.   -  person Kerrek SB    schedule 18.09.2012
comment
rand плох во многих отношениях, и это один из них.   -  person Keith Randall    schedule 18.09.2012


Ответы (4)


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

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

Итак, когда вы заполняете генератор с помощью srand(74), он всегда будет генерировать одну и ту же строку чисел каждый раз. Когда вы заполняете генератор с помощью srand(75), он сгенерирует другую строку чисел и т. Д.

Обычный способ обеспечить каждый раз разный вывод - всегда предоставлять другое начальное значение, обычно это делается путем заполнения генератора текущим временем в секундах / миллисекундах, например srand(time(NULL)).

РЕДАКТИРОВАТЬ: вот сеанс Python, демонстрирующий это поведение. Это вполне ожидаемо.

>>> import random

Если мы заполним генератор одним и тем же номером, он всегда будет выводить одну и ту же последовательность:

>>> random.seed(500)
>>> [random.randint(0, 100) for _ in xrange(20)]
[80, 95, 58, 25, 76, 37, 80, 34, 57, 79, 1, 33, 40, 29, 92, 6, 45, 31, 13, 11]
>>> random.seed(500)
>>> [random.randint(0, 100) for _ in xrange(20)]
[80, 95, 58, 25, 76, 37, 80, 34, 57, 79, 1, 33, 40, 29, 92, 6, 45, 31, 13, 11]
>>> random.seed(500)
>>> [random.randint(0, 100) for _ in xrange(20)]
[80, 95, 58, 25, 76, 37, 80, 34, 57, 79, 1, 33, 40, 29, 92, 6, 45, 31, 13, 11]

Если мы дадим ему другое семя, даже немного другое, числа будут полностью отличаться от старого семени, но все равно останутся такими же, если используется то же (новое) семя:

>>> random.seed(501)
>>> [random.randint(0, 100) for _ in xrange(20)]
[64, 63, 24, 81, 33, 36, 72, 35, 95, 46, 37, 2, 76, 21, 46, 68, 47, 96, 39, 36]
>>> random.seed(501)
>>> [random.randint(0, 100) for _ in xrange(20)]
[64, 63, 24, 81, 33, 36, 72, 35, 95, 46, 37, 2, 76, 21, 46, 68, 47, 96, 39, 36]
>>> random.seed(501)
>>> [random.randint(0, 100) for _ in xrange(20)]
[64, 63, 24, 81, 33, 36, 72, 35, 95, 46, 37, 2, 76, 21, 46, 68, 47, 96, 39, 36]

Как сделать так, чтобы наша программа каждый раз вел себя по-разному? Если мы предоставим одно и то же семя, оно всегда будет вести себя одинаково. Мы можем использовать функцию time.time(), которая будет выдавать другое число каждый раз, когда мы ее вызываем:

>>> import time
>>> time.time()
1347917648.783
>>> time.time()
1347917649.734
>>> time.time()
1347917650.835

Так что, если мы продолжим повторно заполнять его с помощью вызова time.time(), мы будем каждый раз получать другую последовательность чисел, потому что семя каждый раз разное:

>>> random.seed(time.time())
>>> [random.randint(0, 100) for _ in xrange(20)]
[60, 75, 60, 26, 19, 70, 12, 87, 58, 2, 79, 74, 1, 79, 4, 39, 62, 20, 28, 19]
>>> random.seed(time.time())
>>> [random.randint(0, 100) for _ in xrange(20)]
[98, 45, 85, 1, 67, 25, 30, 88, 17, 93, 44, 17, 94, 23, 98, 32, 35, 90, 56, 35]
>>> random.seed(time.time())
>>> [random.randint(0, 100) for _ in xrange(20)]
[44, 17, 10, 98, 18, 6, 17, 15, 60, 83, 73, 67, 18, 2, 40, 76, 71, 63, 92, 5]

Конечно, даже лучше, чем постоянно пересевать, - это засеять один раз и продолжать дальше:

>>> random.seed(time.time())
>>> [random.randint(0, 100) for _ in xrange(20)]
[94, 80, 63, 66, 31, 94, 74, 15, 20, 29, 76, 90, 50, 84, 43, 79, 50, 18, 58, 15]
>>> [random.randint(0, 100) for _ in xrange(20)]
[30, 53, 75, 19, 35, 11, 73, 88, 3, 67, 55, 43, 37, 91, 66, 0, 9, 4, 41, 49]
>>> [random.randint(0, 100) for _ in xrange(20)]
[69, 7, 25, 68, 39, 57, 72, 51, 33, 93, 81, 89, 44, 61, 78, 77, 43, 10, 33, 8]
person Claudiu    schedule 17.09.2012

Каждый вызов rand() возвращает следующее число в предопределенной последовательности, где начальным номером является начальное число, переданное в srand(). Вот почему он называется генератором псевдо случайных чисел, а не генератором случайных чисел.

person ninjalj    schedule 17.09.2012

rand() реализуется генератором псевдослучайных чисел.

Распределение номеров, сгенерированных последовательными вызовами rand(), имеет свойства случайных чисел, но порядок заранее определен. «Стартовый» номер определяется семенем, которое вы предоставляете.

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

person Dancrumb    schedule 17.09.2012
comment
Вы неправильно поняли, четыре приведенных выше фрагмента кода не являются частью одного файла кода. - person user1676037; 18.09.2012
comment
Собственно, я это понимал; однако суть в том, что вы не должны ожидать случайного поведения, если вызовете seed, а затем rand и сделаете это несколько раз. Вы будете наблюдать случайное поведение только в том случае, если вызовете rand несколько раз после вызова seed. - person Dancrumb; 18.09.2012

Создание «случайного» числа независимо от реализации зависит от расходящейся бесконечной последовательности. Бесконечная последовательность генерируется с использованием начального числа случайной функции и фактически является псевдослучайным из-за своей природы. Это объяснит вам, почему ваше число на самом деле очень зависит от семени, которое вы даете функции.

В некоторых реализациях последовательность только одна, и начальное число является начальным членом последовательности. В других есть разные последовательности в зависимости от семени. Если начальное число не указано, оно определяется внутренними «часами».

Число усекается при использовании верхней и нижней границ для вашего случайного числа путем выполнения соответственно randValue % upperBound и randValue + lowerBound. Случайная реализация очень похожа на хеш-функции. В зависимости от архитектуры верхняя граница случайного значения устанавливается в зависимости от того, какое это наибольшее целое / двойное число, которое оно может выполнить, если не установлено пользователем ниже.

person Konstantin Dinev    schedule 17.09.2012