Я не первый, кто указывает, что вам следует звонить srand
только один раз, но я объясню почему :
Чем чаще вы звоните srand
, тем меньше случайным образом получается rand
.
Функция rand
является генератором случайных чисел псевдо . Это означает, что он генерирует числа, которые выглядят случайными и имеют математические свойства, соответствующие случайности, но на самом деле они не случайны. Вывод rand
на самом деле является фиксированной, полностью детерминированной последовательностью чисел.
Или, скорее, он производит одну из большого семейства полностью детерминированных последовательностей. Вы выбираете, какую из этих последовательностей вы хотите, предоставив начальное значение, используя srand
. Когда вы дадите srand
начальное число x
, следующий вывод rand
будет первым номером псевдослучайной (но полностью детерминированной!) Последовательности, идентифицированной начальным значением x
. Другими словами:
int foo(int x)
{
srand(x);
return rand();
}
Возвращает разные значения для разных входов, но для данного x
всегда будет возвращать одинаковое значение. Совсем не случайно!
Это на самом деле полезная функция, так как если вы обнаружите ошибку в программе, которая зависит от вывода rand
, вы можете надежно воспроизвести ошибку, предоставив то же начальное значение для srand
, чтобы получить то же самое последовательность из rand
и то же поведение из вашей программы.
Причина, по которой вам нужно один раз вызвать srand
, заключается в том, что в противном случае ваша программа всегда будет получать одинаковую последовательность чисел из rand
(последовательность, указанная с помощью seed 1
). Причина, по которой вы не хотите вызвать srand
более одного раза (в большинстве случаев), заключается в том, что вы затем несколько раз заставляете rand
возвращаться к началу его последовательностей, вместо того, чтобы дать ему один из их в полном объеме. Хотя любая заданная последовательность обладает свойствами случайности, последовательность начала последовательности не обязательно обладает этим свойством.
Очевидно, что особенно плохо, если вы повторно вызываете srand
с одним и тем же seed, потому что тогда вы заставляете rand
вернуться к началу одна и та же последовательность каждый раз, поэтому rand
всегда будет выдавать одинаковое значение - именно то, что вам не нужно.
Причина, по которой вы обычно видите srand(time(NULL))
, заключается в том, что время, вероятно, будет различным для любых двух вызовов данной программы, что означает, что при каждом запуске программы будет использоваться другая псевдослучайная последовательность. Но time
возвращает время только с точностью до секунд, поэтому, если вы делаете это несколько раз в течение одного вызова программы, как у вас, и между вызовами srand
проходит менее одной секунды, вы будете повторно - посев с тем же семенем, с нелепыми результатами, как вы наблюдали.
Итог: звоните srand
ровно один раз, перед первым использованием rand
. Поверьте, что разработчики библиотеки C написали приличный генератор псевдослучайных чисел, и не пытайтесь «увеличить случайность», пытаясь компенсировать проблемы, которых не существует.