Почему rand () выдает одинаковую последовательность чисел при каждом запуске? - PullRequest
30 голосов
/ 27 февраля 2012

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

Пример:

#include <iostream>
#include <cstdlib>

using namespace std;

int random (int low, int high) {
    if (low > high) return high;
    return low + (rand() % (high - low + 1));
}
int main (int argc, char* argv []) {
    for (int i = 0; i < 5; i++) cout << random (2, 5) << endl;
}

Выход:

3
5
4
2
3

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

Ответы [ 6 ]

49 голосов
/ 27 февраля 2012

Не задано начальное число для генератора случайных чисел.

Если вы позвоните srand(time(NULL)), вы получите более случайные результаты:

#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;

int main() {
    srand(time(NULL));
    cout << rand() << endl;
    return 0;
}

Причина в том, что случайное число, сгенерированное функцией rand(), на самом деле не случайно. Это просто трансформация. Википедия дает лучшее объяснение значения генератора псевдослучайных чисел: детерминированного генератора случайных битов. Каждый раз, когда вы вызываете rand(), он берет начальное и / или последнее сгенерированное случайное число (а) (стандарт C не определяет используемый алгоритм, хотя C ++ 11 имеет средства для определения некоторых популярных алгоритмов), запускает математическая операция над этими числами и возвращает результат. Поэтому, если начальное состояние каждый раз одно и то же (как и в случае, если вы не набираете srand с действительно случайным числом), вы всегда будете получать одни и те же «случайные» числа.

Если вы хотите узнать больше, вы можете прочитать следующее:

http://www.dreamincode.net/forums/topic/24225-random-number-generation-102/

http://www.dreamincode.net/forums/topic/29294-making-pseudo-random-number-generators-more-random/

15 голосов
/ 27 февраля 2012

Если вы позвоните rand() без предварительного вызова srand(), он будет действовать так, как если бы вы позвонили srand(1) неявно. Соответствующий бит стандарта C99 7.20.2.2 The srand function (на котором основан cstdlib) гласит:

Если rand вызывается до того, как были сделаны какие-либо вызовы srand, генерируется та же последовательность, что и при первом вызове srand со начальным значением 1.

Другими словами, вы будете каждый раз получать одну и ту же последовательность. Вы можете изменить свой main на:

int main (int argc, char* argv []) {
    srand (time (0));  // needs ctime header.
    for (int i = 0; i < 5; i++)
        cout << random (2, 5) << endl;
    wait ();
}

чтобы исправить это, при условии, что вы запускаете его не чаще, чем раз в секунду.

Как уже упоминалось, для этого вам понадобится заголовок ctime. Вы также должны потянуть cstdlib, поскольку там живут rand и srand. Также обычно рекомендуется использовать заголовки cXXX, а не XXX.h (например, cmath вместо math.h).

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

#include <iostream>
#include <cstdlib>
#include <ctime>
#include <cmath>

void wait () {
    int e;
    std::cin >> e;
}

int random (int low, int high) {
    if (low > high) return high;
    return low + (std::rand() % (high - low + 1));
}

int main (int argc, char* argv []) {
    std::srand (std::time (0));
    for (int i = 0; i < 5; i++)
        std::cout << random (2, 5) << '\n';
    wait ();
}

, который дает другую последовательность при каждом запуске, в любом случае, несколько раз. Очевидно, что существует жесткое ограничение на то, когда данные будут повторяться (имеется только 4 5 возможностей), а «случайный» характер вывода означает, что он может повторяться и раньше: -)

3 голосов
/ 27 февраля 2012

Это функция функции rand().

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

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

Обратите внимание, однако, что ни C, ни C ++ не определяют числовую последовательность из rand(). Поэтому, если вам нужны гарантированные последовательности на разных платформах, используйте один из новых генераторов случайных чисел в C ++ 11 (например, mersenne twister ), сверните свои собственные (однако некоторые генераторы почти тривиальны для понимания, потому что большинство они полагаются на определенное поведение переполнения, их реализация может быть не тривиальной), или используют сторонний компонент (например, boost :: random).

1 голос
/ 27 февраля 2012

Вам нужно заполнить генератор случайных чисел (см. Функцию «srand»). Предполагая, что вы не делаете криптографию, возможно, достаточно заполнить ее выводом 'time'.

0 голосов
/ 21 марта 2013

используйте randomize (). Это автоматически отбирает значение. Или, если вы хотите использовать rand (), вы можете заполнить его с помощью srand (seedvalue); начальное значение может быть как системное время, которое каждый раз будет давать вам разные случайные числа

0 голосов
/ 27 февраля 2012

Вы на самом деле получаете псевдо случайные числа. Чтобы сделать их «более случайными», вы можете запустить генератор случайных чисел, используя то, что «меняется» (чаще всего текущее время).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...