Чтение онлайн

ЖАНРЫ

Linux программирование в примерах
Шрифт:

ЗАМЕЧАНИЕ. Природа случайности, генерация случайных чисел и их «качество» являются обширными темами, выходящими за рамки данной книги. Мы предоставляем введение в доступные функции API, но это все, что мы можем сделать Другие источники с более подробной информацией см в разделе 12.9 «Рекомендуемая литература»

Компьютеры по своему строению являются детерминистическими. Одно и то же вычисление с одними и теми же входными данными всегда должно давать одни и те же результаты. Соответственно, они не годятся для генерации истинно случайных чисел, то есть последовательностей чисел, в которых каждое число в последовательности полностью независимо от числа (или

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

Многие методы предоставления последовательностей псевдослучайных чисел работают посредством осуществления каждый раз одного и того же вычисления с начальным значением (seed). Сохраненное начальное значение затем обновляется для использования в следующий раз. API предоставляет способ указания нового начального значения. Каждое начальное значение дает одну и ту же последовательность псевдослучайных чисел, хотя различные начальные числа дают (должны давать) различные последовательности.

12.6.1. Стандартный С:

rand
и
srand

Стандартный С определяет две связанные функции для псевдослучайных чисел.

#include <stdlib.h> /* ISO С */

int rand(void);

void srand(unsigned int seed);

rand
каждый раз после вызова возвращает псевдослучайное число в диапазоне от 0 до
RAND_MAX
(включительно, насколько мы можем судить по стандарту C99). Константа
RAND_MAX
должна быть по крайней мере 32 767; она может быть больше.

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

Следующая программа,

ch12-rand.c
, использует
rand
для вывода граней игральных костей.

1 /* ch12-rand.c --- генерирует игральные кости, используя rand. */

2

3 #include <stdio.h>

4 #include <stdlib.h>

5

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

7 " ",

8 " * ", /* 1 */

9 " ",

10

11 " ",

12 " * * ", /* 2 */

13 " ",

14

15 " ",

16 " * * * ", /* 3 */

17 " ",

18

19 " * * ",

20 " ", /* 4 */

21 " * * ",

22

23 " * * ",

24 " * ", /* 5 */

25 " * * ",

26

27 " * * * ",

28 " ", /* 6 */

29 " * * * ",

30 };

31

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

33

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

35 {

36 int nfaces;

37 int i, j, k;

38

39 if (argc !=2) {

40 fprintf(stderr, "usage: %s number-die-faces\n", argv[0]);

41 exit(1);

42 }

43

44 nfaces = atoi(argv[1]);

45

46 if (nfaces <= 0) {

47 fprintf(stderr, "usage: %s number-die-faces\n", argv[0]);

48 fprintf(stderr, "\tUse a positive number!\n");

49 exit(1);

50 }

51

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

53 j = rand % 6; /* force to range 0 <= j <= 5 */

54 printf("+-------+\n" );

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

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

57 printf ("+-------+\n\n");

58 }

59

60 return 0;

61 }

Эта программа использует простую ASCII-графику для распечатывания подобия грани игральной кости. Вы вызываете ее с числом граней для вывода. Это вычисляется в строке 44 с помощью

atoi
. (В общем,
atoi
следует избегать в коде изделия, поскольку она не осуществляет проверку на ошибки или переполнение, также как не проверяет вводимые данные.)

Ключевой является строка 53, которая преобразует возвращаемое значение

rand
в число от нуля до пяти, используя оператор остатка,
%
. Значение '
j * 3
' действует в качестве начального индекса массива
die_faces
для трех строк, составляющих каждую грань кости. Строки 55 и 56 выводят саму грань. При запуске появляется вывод наподобие этого:

$ ch12-rand 2 /* Вывести две кости */

+-------+

| |

| * * |

| |

+-------+

+-------+

| * * |

| * |

| * * |

+-------+

Интерфейс

rand
восходит еще к V7 и PDP-11. В частности, на многих системах результатом является лишь 16-разрядное число, что значительно ограничивает диапазон чисел, которые могут быть возвращены. Более того, используемый им алгоритм по современным стандартам считается «слабым». (Версия
rand
GLIBC не имеет этих проблем, но переносимый код должен быть написан со знанием того, что
rand
не является лучшим API для использования.)

Поделиться с друзьями: