srand в C++: инициализация случайного генератора

Привет! В этой статье мы поговорим о функции srand. Эта функция используется в C++ для инициализации генератора случайных чисел. Начнем мы с разбора этой функции на примерах, а закончим упражнениями для закрепления материала.

Иллюстрация srand

Инициализация псевдо-случайных чисел при помощи srand

Функция srand доступна нам после подключения заголовочного файла <stdlib.h> в C или <cstdlib> в C++. Эта функция выглядит следующим образом:

void srand (unsigned int seed);
  • Единственным аргументом функция принимает зерно (seed), которое будет использоваться для расчета цепочки случайных чисел.
  • Функция ничего не возвращает.

Давайте посмотрим на простой пример использования этой функции в паре с rand:

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

int main() {
  srand(123);

  cout << "1. " << rand() << endl;
  cout << "2. " << rand() << endl;
  cout << "3. " << rand() << endl;

  return 0;
}

Вывод:

1. 2067261
2. 384717275
3. 2017463455

При этом, если мы запустим эту программу еще раз, числа не изменятся:

1. 2067261
2. 384717275
3. 2017463455

Что будет выведено на экран при следующем коде?

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

int main() {
  srand(456);

  cout << "A. " << rand() << endl;
  cout << "B. " << rand() << endl;
  srand(456);
  cout << "C. " << rand() << endl;
  cout << "D. " << rand() << endl;

  return 0;
}
Значения A и B одинаковые, значения C и D разные
Значения A и C одинаковые, значения B и D одинаковые
Значения A, B, C, и D все разные
Значения A и B разные, значения C и D одинаковые

Чтобы числа менялись, нужно менять зерно для каждого запуска. Это можно сделать несколькими способами:

  • использовать текущие время;
  • попросить пользователя выбрать зерно при старте;
  • использовать другой генератор случайных чисел для инициализации;

Текущие время как зерно для случайных чисел

Самым простым и удобным способ инициализировать генератор случайных чисел является использование текущего времени. Если вы не запускаете программу несколько раз в секунду, то достаточно воспользоваться функцией time:

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

int main() {
  int seed = time(NULL);
  srand(seed);

  cout << "1. " << rand() << endl;
  cout << "2. " << rand() << endl;
  cout << "3. " << rand() << endl;

  return 0;
}

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

1. 784904114
2. 2038884124
3. 128916889

И еще один:

1. 786164639
2. 1749691329
3. 1568588132

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

Ввод зерна пользователем

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

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

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

int main() {
  int age;
  cout << "Введите ваш возраст: ";
  cin >> age;

  srand(age);

  int salary = rand() % 100500 + 1;

  cout << "Ваша звездная зарплата: $" << salary << endl;

  return 0;
}
Введите ваш возраст: 25
Ваша звездная зарплата: $18176

Использование стороннего генератора случайных чисел

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

Давайте воспользуемся классом random_device из файла <random> для получения системных случайных чисел:

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

int main() {
  random_device system_rand;
  int seed = system_rand();

  srand(seed);

  cout << "1. " << rand() << endl;
  cout << "2. " << rand() << endl;
  cout << "3. " << rand() << endl;

  return 0;
}

Вывод:

1. 524804038
2. 666128437
3. 788388848

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

Упражнения

  1. Использование srand с текущим временем:
    Напишите программу, которая использует функцию srand с текущим временем в качестве зерна. Ваша программа должна генерировать и выводить пять случайных чисел. Запустите программу несколько раз и обратите внимание на полученные результаты.

  2. Собственное зерно для srand:
    Создайте программу, которая просит пользователя ввести свою любимую книгу, фильм или песню. Используйте длину введенной строки в качестве зерна для функции srand. Генерируйте и выводите 3 случайных числа на основе этого зерна.

  3. Анализ поведения srand:
    Модифицируйте программу из первого пункта, чтобы выводить пять случайных чисел с зерном, заданным пользователем. Запустите программу несколько раз с одним и тем же зерном и затем с разными значениями. Проанализируйте и опишите свои наблюдения.

Обсуждение