rand() не дает мне случайное число (даже когда используется srand())

Ладно, я начинаю сходить с ума. Все, что я хочу сделать, это случайное число от 0 до 410, и в соответствии с это страница, мой код должен это делать. И поскольку мне нужно случайное число, а не псевдослучайное число, я также использую srand() таким образом, что, например. этот поток сказал мне сделать. Но это не работает. Все, что я получаю, это число, которое зависит от того, сколько времени прошло с момента моей последней казни. Если я, например. выполнить его снова так быстро, как я могу, число обычно на 6 чисел выше, чем последнее число, и если я жду дольше, оно выше и т. д. Когда оно достигает 410, оно возвращается к 0 и начинается все сначала. Что мне не хватает?

Редактировать: И да, если я удалю строку srand(time(NULL));, я просто буду получать один и тот же номер (41) каждый раз, когда запускаю программу. Это даже не псевдослучайное, это просто статическое число. Простое копирование первой строки кода из статьи, на которую я ссылался выше, по-прежнему дает мне номер 41 все время. Я звезда в продолжении "Числа 23", или я что-то пропустил?

int main(void) {

    srand(time(NULL));
    int number = rand() % 410;

    std::cout << number << std::endl;

    system("pause");

}

person Jonatan Stenbacka    schedule 12.01.2015    source источник
comment
want a random number and not a pseudo-random number - nope srand только гарантирует, что будет возвращен другой. Тем не менее последовательность является псевдослучайной   -  person Ivaylo Strandjev    schedule 12.01.2015
comment
Вы были Лававехедом! См.: channel9.msdn.com/Events/GoingNative/2013/ -- в частности, ваша точная проблема обсуждается в 3:30 мин.   -  person Damon    schedule 12.01.2015
comment
Что вы подразумеваете под случайным числом, а не псевдослучайным числом? Если вам просто нужно число, которое явно не связано с начальным числом, вызовите rand() один или несколько раз, прежде чем использовать значение из него; похоже, у вас довольно плохая реализация rand, которая возвращает начальное значение в качестве первого значения. Если вам действительно нужно настоящее случайное число, то вы не можете получить его только с помощью программного обеспечения. std::random_device может дать вам это, но только при наличии подходящего аппаратного устройства. для его использования.   -  person Mike Seymour    schedule 12.01.2015


Ответы (5)


Это то, что вы получаете за использование устаревшей генерации случайных чисел.

rand выдает фиксированную последовательность чисел (что само по себе хорошо), и делает это очень и очень плохо.

Вы сообщаете rand через srand, с чего в последовательности начать. Поскольку ваша «начальная точка» (называемая seed кстати) зависит от количества секунд, прошедших с 1.1.1970 0:00:00 UTC, ваш вывод, очевидно, зависит от времени.

Правильный способ сделать то, что вы хотите, — это использовать C++11 <random>библиотека. В вашем конкретном примере это будет выглядеть примерно так:

std::mt19937 rng (std::random_device{}());
std::uniform_int_distribution<> dist (0, 409);

auto random_number = dist(rng);

Для получения дополнительной информации о недостатках rand и преимуществах <random> см. это.

В качестве последнего замечания, заполнение std::mt19937, как я сделал выше, не совсем оптимально, потому что пространство состояний MT намного больше, чем 32-битное, которое вы получаете в результате одного вызова std::random_device{}(). Это не проблема для игрушечных программ и ваших стандартных школьных заданий, но для справки: Здесь - это мой подход к заполнению всего пространства состояний MT, а также несколько полезных советов в ответах.

person Baum mit Augen    schedule 12.01.2015

Из руководства:

time() возвращает время в виде количества секунд с начала эпохи, 1970-01-01 00:00:00 +0000 (UTC).

Это означает, что если вы дважды запустите свою программу оба раза в одну и ту же секунду, вы инициализируете srand одним и тем же значением и получите одинаковое состояние PRNG.

И если вы удалите инициализацию через вызов srand, вы всегда будете получать точно такую ​​же последовательность чисел из rand.

person tumdum    schedule 12.01.2015

Боюсь, вы не можете получить там действительно случайные числа. Встроенные функции предназначены для предоставления только псевдослучайных чисел. Более того, используя srand и rand, потому что первый использует тот же подход, что и второй. Если вы хотите приготовить настоящие случайные числа, вы должны найти правильный источник энтрофии, работающий, например, с атмосферным шумом, как подход www.random.org.

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

person mekoda    schedule 12.01.2015

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

Поэтому вам нужно обойтись псевдогенератором. Но использовать их нужно осторожно.

Функция rand предназначена для возврата числа от 0 до RAND_MAX способом, который, вообще говоря, удовлетворяет статистическим свойствам равномерного распределения. В лучшем случае вы можете ожидать, что среднее значение выпавших чисел будет 0.5 * RAND_MAX, а дисперсия - RAND_MAX * RAND_MAX / 12.

Обычно реализация rand представляет собой линейный конгруэнтный генератор, что в основном означает, что возвращаемое число является функцией предыдущего числа. Это может дать удивительно хорошие результаты и позволяет вам заполнить генератор функцией srand.

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

Что вам нужно сделать, так это сделать только один вызов srand, а затем нарисовать последовательность чисел, используя rand. Вы не можете легко сделать это так, как вы все настроили. Но есть альтернативы; вы можете переключиться на генератор случайных чисел (скажем, твистер Мерсенна), который позволяет вам нарисовать (n)-й член, и вы можете передать значение n в качестве аргумента командной строки.

И последнее замечание: я бы не стал использовать модуль при рисовании числа. Это создаст статистическую погрешность, если ваш модуль не кратен RAND_MAX.

person Bathsheba    schedule 12.01.2015

Попробуйте изменить NULL во времени (NULL) на время (0) (это даст вам текущее системное время). Если это не сработает, вы можете попытаться преобразовать время (0) в мс, выполнив time (0) * 1000.

person Francois Le Brun    schedule 12.01.2015
comment
Спасибо, но я не работал. Изменение его на time(0) ничего не дало, а изменение на time(0)*1000 изменило ошибку на аналогичную, но вместо этого с убывающими числами. - person Jonatan Stenbacka; 12.01.2015
comment
NULL и 0 имеют одинаковые значения и в данном случае не имеют значения. Умножение секунд на константу никак не помогает, когда они используются в качестве случайного начального числа. - person eerorika; 12.01.2015