Почему я всегда получаю одинаковую последовательность случайных чисел с помощью rand ()? - PullRequest
49 голосов
/ 10 июля 2009

Я впервые пробую случайные числа с C (я скучаю по C #). Вот мой код:

int i, j = 0;
for(i = 0; i <= 10; i++) {
    j = rand();
    printf("j = %d\n", j);
}

с этим кодом, я получаю одну и ту же последовательность каждый раз, когда запускаю код. Но он генерирует разные случайные последовательности, если я добавлю srand(/*somevalue/*) перед циклом for. Кто-нибудь может объяснить, почему?

Ответы [ 11 ]

81 голосов
/ 10 июля 2009

Вы должны посеять это. Хорошая идея - посеять со временем:

srand()

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main ()
{
  srand ( time(NULL) );
  printf ("Random Number: %d\n", rand() %100);
  return 0;
}

Вы получаете ту же последовательность, потому что rand() автоматически засевается со значением 1, если вы не вызываете srand().

Редактировать

По комментариям

rand() вернет число от 0 до RAND_MAX (определено в стандартной библиотеке). Использование оператора по модулю (%) дает остаток от деления rand() / 100. Это заставит случайное число находиться в диапазоне 0-99. Например, чтобы получить случайное число в диапазоне 0-999, мы применили бы rand() % 1000.

33 голосов
/ 10 июля 2009

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

Вы можете установить «начальное число» генератора случайных чисел с помощью функции srand (вызывать srand только один раз в программе). Один из распространенных способов получить различные последовательности из генератора rand () - установить Начальное время или идентификатор процесса:

srand (время (NULL)); или srand (getpid ()); в начале программы.

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

19 голосов
/ 10 июля 2009

Цитировать из man rand :

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

Если начальное значение не указано, функция rand () автоматически отобранный со значением 1.

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

11 голосов
/ 10 июля 2009

Здесь много ответов, но никто, похоже, не действительно объяснил, почему rand () всегда генерирует одну и ту же последовательность, учитывая одно и то же семя - или даже то, что семя действительно делает , Так что вот так.

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

state_t rand_state = INITIAL_STATE;

state_t calculate_next_state(state_t s);
int calculate_return_value(state_t s);

int rand(void)
{
    rand_state = calculate_next_state(rand_state);
    return calculate_return_value(rand_state);
}

Теперь вы можете видеть, что каждый раз, когда вы вызываете rand (), он заставляет rand_state двигаться на один шаг по заранее определенному пути. Случайные значения, которые вы видите, основаны только на том, где вы находитесь на этом пути, поэтому они также будут следовать заранее определенной последовательности.

Теперь вот где приходит srand (). Он позволяет вам перейти к другой точке пути:

state_t generate_random_state(unsigned int seed);

void srand(unsigned int seed)
{
    rand_state = generate_random_state(seed);
}

Точная информация о state_t, Calculate_next_state (), calc_return_value () и generate_random_state () может варьироваться от платформы к платформе, но обычно они довольно просты.

Из этого видно, что при каждом запуске вашей программы rand_state будет запускаться с INITIAL_STATE (что эквивалентно generate_random_state (1)) - поэтому вы всегда получаете одну и ту же последовательность, если не используете srand ().

9 голосов
/ 10 июля 2009

Если я помню цитату из основополагающей работы Кнута «Искусство компьютерного программирования» в начале главы «Генерация случайных чисел», она выглядит так:

«Любой, кто пытается генерировать случайные числа математическими средствами, технически говоря, находится в состоянии греха».

Проще говоря, стандартные генераторы случайных чисел являются алгоритмами, математическими и предсказуемыми на 100%. На самом деле это хорошо во многих ситуациях, когда желательна повторяющаяся последовательность «случайных» чисел - например, для определенных статистических упражнений, где вы не хотите «колебания» в результатах, которые действительно случайные данные вводят благодаря эффекты кластеризации.

Хотя получение битов «случайных» данных с аппаратного обеспечения компьютера является второй популярной альтернативой, оно также не является действительно случайным - хотя чем сложнее операционная среда, тем больше возможностей для случайности или, по крайней мере, непредсказуемости.

Истинно случайные генераторы данных, как правило, обращаются к внешним источникам. Радиоактивный распад является фаворитом, как и поведение квазаров. Все, чьи корни в квантовых эффектах, фактически случайно - очень к раздражению Эйнштейна.

7 голосов
/ 10 июля 2009

Генераторы случайных чисел на самом деле не случайны, они, как и большинство программ, полностью предсказуемы. Что делает rand, так это создает другое псевдослучайное число каждый раз, когда оно называется «Одно», которое кажется случайным. Для того, чтобы использовать его правильно, вам нужно дать ему другую отправную точку.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main ()
{
  /* initialize random seed: */
  srand ( time(NULL) );

  printf("random number %d\n",rand());
  printf("random number %d\n",rand());
  printf("random number %d\n",rand());
  printf("random number %d\n",rand());

  return 0;
}
2 голосов
/ 10 июля 2009

rand () возвращает следующее (псевдо) случайное число в серии. Происходит то, что у вас один и тот же сериал при каждом запуске (по умолчанию «1»). Чтобы начать новую серию, вы должны вызвать srand (), прежде чем начать вызывать rand ().

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

srand (time (0));
2 голосов
/ 10 июля 2009

Это от http://www.acm.uiuc.edu/webmonkeys/book/c_guide/2.13.html#rand:

Декларация:

void srand(unsigned int seed); 

Эта функция запускает генератор случайных чисел, используемый функцией rand. Seeding srand с тем же начальным значением заставит rand вернуть ту же последовательность псевдослучайных чисел. Если srand не вызывается, rand действует так, как будто srand (1) вызван.

0 голосов
/ 14 ноября 2009

Никто из вас, ребята, не отвечает на его вопрос.

с этим кодом я получаю одинаковую последовательность каждый раз, когда код, но он генерирует случайные последовательности, если я добавляю srand (/ somevalue /) перед циклом for. может кто-нибудь объяснить почему?

Из того, что сказал мне мой профессор, он используется, если вы хотите убедиться, что ваш код работает правильно, и посмотреть, если что-то не так или вы можете что-то изменить.

0 голосов
/ 10 июля 2009

Заполнение rand()

void srand (unsigned int seed)

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

Чтобы создавать разные псевдослучайные ряды при каждом запуске вашей программы, выполните srand (time (0))

...