Книга: Linux программирование в примерах
12.6.1. Стандартный С: rand() и srand()
12.6.1. Стандартный С: rand()
и srand()
Стандартный С определяет две связанные функции для псевдослучайных чисел.
#include <stdlib.h> /* ISO С */
каждый раз после вызова возвращает псевдослучайное число в диапазоне от 0 до
int rand(void);
void srand(unsigned int seed);
rand()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-facesn", argv[0]);
41 exit(1);
42 }
43
44 nfaces = atoi(argv[1]);
45
46 if (nfaces <= 0) {
47 fprintf(stderr, "usage: %s number-die-facesn", 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 ("+-------+nn");
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 для использования.)
ch12-rand.c
использует для получения значения в определенном интервале простую методику: оператор %
. Эта методика использует младшие биты возвращенного значения (как при десятичном делении, когда остаток отделения на 10 или 100 использует одну или две младшие десятичные цифры). Оказывается, исторический генератор rand()
производил лучшие случайные значения в средних и старших битах по сравнению с младшими битами. Поэтому, если вы должны использовать rand()
, постарайтесь избежать младших битов. Справочная страница GNU/Linux rand(3) цитирует «Числовые рецепты на С»[129], которая рекомендует эту методику:
j = 1+ (int)(10.0*rand()/(RAND_MAX+1.0)); /* для числа от 1 до 10 */
- 12.6. Псевдослучайные числа
- Стандартный механизм представлений на базе WebForms
- Как сменить стандартный значок?
- 12.6.2. Функции POSIX: random() и srandom()
- Using a Pseudorandom Number Generator
- 14.1.4. Стандартный ввод и вывод
- PROJECT 10.2 — Random Number Generator
- 1.3. Стандартный С против оригинального С
- Стандартный производственный процесс организации (СППО)
- Наш ответ хакерам, или Как сделать brandname из старшего лейтенанта Евгений Касперский
- ICQ (Айсикью), Qip (Кип), Miranda (Миранда)
- random_shuffle