12.6.2. Функции POSIX: random() и srandom()

12.6.2. Функции POSIX: random() и srandom()

BSD 4.3 ввело random() и сопровождающие ее функции. Эти функции используют намного более подходящий генератор случайных чисел, который возвращает 31-разрядное значение. Теперь они входят в расширение XSI, стандартизованное POSIX:

#include <stdlib.h> /* XSI */

long random(void);

void srandom(unsigned int seed);

char *initstate(unsigned int seed, char *state, size_t n);

char *setstate(char *state);

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

long random(void);

Возвращает число в диапазоне от 0 до 231-1. (Хотя справочная страница GNU/Linux random(3) говорит между 0 и RAND_MAX, это верно лишь для систем GLIBC, где RAND_MAX равен 231-1. На других системах RAND_MAX может быть меньше. POSIX явно называет диапазон от 0 до 231-1.)

void srandom(unsigned int seed);

Устанавливает начальное число. Если srandom() никогда не вызывается, по умолчанию используется 1.

char *initstate(unsigned int seed, char *state, size_t n);

Инициализирует массив state информацией для использования при генерации случайных чисел, seed является начальным значением, как для srandom(), а n является числом байтов в массиве state.

n должен равняться одному из значений 8, 32, 64, 128 или 256. Большие значения дают лучшие последовательности случайных чисел. Значения меньше 8 заставляют random() использовать простой генератор случайных чисел, сходный с rand(). Значения больше 8, не равные одному из значений в списке, округляются до ближайшего подходящего значения.

char *setstate(char *state);

Устанавливает внутреннее состояние в соответствии с массивом state, который должен быть инициализирован посредством initstate(). Это позволяет переключаться по желанию между различными состояниями, предоставляя множество генераторов случайных чисел.

Если initstate() и setstate() никогда не вызывались, random() использует массив внутреннего состояния размером 128.

Массив state непрозрачен; вы инициализируете его с помощью initstate() и передается функции random() посредством setstate(), но в другом отношении вам не нужно заглядывать в него. Если вы используете initstate() и setstate(). srandom() вызывать не нужно, поскольку начальное значение включено в информацию о состоянии. ch12-random.c использует эти процедуры вместо rand(). Используется также обычная методика, которая заключается в использовании в качестве начального значения генератора случайных чисел времени дня, добавленного к PID.

1  /* ch12-random.c --- генерация вращения костей с использованием random(). */

2

3  #include <stdio.h>

4  #include <stdlib.h>

5  #include <sys/types.h>

6  #include <unistd.h>

7

8  char *die_faces[] = { /* Управляет ASCII графика! */

    /* ... как раньше ... */

32 };

33

34 /* main --- выводит N различных граней кубиков */

35

36 int main(int argc, char **argv)

37 {

38  int nfaces;

39  int i, j, k;

40  char state[256];

41  time_t now;

42

    /* ... проверка args, вычисление nfaces, как раньше ... */

55

56  (void)time(&now); /* В качестве начального значения используются время дня и PID */

57  (void) initstate((unsigned int)(now + getpid()), state, sizeof state);

58  (void)setstate(state);

59

60  for (i = 1; i <= nfaces; i++) {

61   j = random() % 6; /* использовать диапазон 0 <= j <= 5 */

62    printf("+-------+ ");

63    for (k = 0; k < 3; k++)

64     printf("|%s| ", die_faces[(j * 3) + k]);

65    printf("+-------+ ");

66  }

67

68  return 0;

69 }

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

Поскольку она создает последовательности случайных чисел лучшего качества, random() является более предпочтительной по сравнению с rand(), и GNU/Linux и все современные системы Unix ее поддерживают.