В чем разница между srand (1) и srand (0)
Я только что обнаружил, что srand(1)
сбрасывает PRNG из C (++) в состояние перед любым вызовом srand
(как определено в reference).
Тем не менее, семя 0, похоже, делает то же самое, или состояние до того, как любой вызов srand
, кажется, использует семя 0.
В чем разница между этими двумя вызовами или по какой причине они делают одно и то же?
Например, этот код (выполняется на Ideone)
#include <stdio.h>
#include <stdlib.h>
int main() {
for (int seed = 0; seed < 4; seed++ ) {
printf( "Seed %d:", seed);
srand( seed );
for(int i = 0; i < 5; i++ )
printf( " %10d", rand() );
printf( "\n");
}
return 0;
}
возвращает
Seed 0: 1804289383 846930886 1681692777 1714636915 1957747793
Seed 1: 1804289383 846930886 1681692777 1714636915 1957747793
Seed 2: 1505335290 1738766719 190686788 260874575 747983061
Seed 3: 1205554746 483147985 844158168 953350440 612121425
Ответы
Ответ 1
Это, вероятно, деталь реализации. Стандарт предусматривает, что случайное семя 1 является особенным, а внутренний регистр вашего конкретного алгоритма случайного генератора, вероятно, инициализируется нулем, тем самым вызывая такую же случайную последовательность для семян (0) и семян (1). Я даже ставлю, что первая строка вашей реализации srand() выглядит так:
if ( seed == 1 ) seed = 0;
для обеспечения стандартно-совместимого поведения.
Как правило, генераторы случайных чисел для rand() и srand() не обязаны давать разные последовательности для разных семян, но одну и ту же последовательность для одного и того же семени. Таким образом, не полагаются на разные семена, генерирующие разные случайные последовательности, и вы должны быть в порядке. Если нет, добро пожаловать в конкретную забаву.
Ответ 2
Как работает glibc:
вокруг строки 181 glibc/stdlib/random_r.c, внутри функции __srandom_r
/* We must make sure the seed is not 0. Take arbitrarily 1 in this case. */
if (seed == 0)
seed = 1;
Но это то, как это делает glibc. Это зависит от реализации стандартной библиотеки C.
Ответ 3
Ни стандарты C, ни С++ не говорят о специфике реализации rand()
и srand()
. Детали остаются почти полностью до разработчика. Стандарт C требует, чтобы:
Если srand затем вызывается с тем же начальным значением, последовательность псевдослучайных чисел должна повторяться. Если rand вызывается до того, как были сделаны вызовы srand, одна и та же последовательность должна быть сгенерирована так, как когда srand сначала вызывается с начальным значением 1.
но он не содержит требования о том, чтобы разные семена должны создавать разные последовательности. По-видимому, в вашей системе семена нулевого и одного имеют тот же эффект. Я предполагаю, что это должно обеспечить обратную совместимость с некоторым программным обеспечением, которое ожидает от srand(0)
до reset PRNG до его начального состояния.
Ответ 4
Если для семени установлено значение 1, генератор повторно инициализируется до его начального значения и выдает те же значения, что и перед любым вызовом rand или srand. Взято из srand ссылка
Ответ 5
При чтении страниц руководства все они утверждают, что "Если не задано начальное значение, функция rand() автоматически засевается значением 1." Вероятно, поэтому ссылка на ссылку, на которую ссылается, указывает, что посев с 1 сбрасывает состояние.
То же самое происходит при посеве с 0 и 1, скорее всего, зависит от реализации и не должно учитываться на всех платформах.
Ответ 6
Функция srand() использует этот аргумент как семя для новой последовательности псевдослучайных чисел, которые будут возвращены последующими вызовами rand(). Если srand() вызывается с тем же начальным значением, последовательность псевдослучайных чисел должна повторяться. Если вызов rand() вызывается до того, как сделаны какие-либо вызовы srand(), одна и та же последовательность должна быть сгенерирована так, как когда srand() сначала вызывается с начальным значением 1.
Возможно, полезно: http://pubs.opengroup.org/onlinepubs/009695399/functions/rand.html
Ответ 7
Причина 1 указана в том, что некоторые генераторы случайных чисел будут застревать в нуле, если семя будет установлено на ноль. Например, сдвиговые регистры и мультипликативные конгруэнтные типы, т.е. r(n+1) = (A * r(n))mod M
.
Многие реализации C используют линейные конгруэнтные r(n+1) = (A * r(n) + B) mod M
, B < > 0, которые не застревают.