список часто задаваемых вопросов comp.lang.c · Вопрос 13.16
В: Как я могу получить случайные целые числа в определенном диапазоне?
A: Очевидный путь,
rand() % N /* POOR */
(который пытается вернуть числа от 0 до N-1) плохо, потому что
Младшие биты многих генераторов случайных чисел вызывают беспокойство
не случайно. (См. Вопрос 13.18 .) Лучший метод - что-то вроде
(int)((double)rand() / ((double)RAND_MAX + 1) * N)
Если вы не хотите использовать число с плавающей запятой, другой метод -
rand() / (RAND_MAX / N + 1)
Если вам просто нужно что-то сделать с вероятностью 1 / N, вы можете использовать
if(rand() < (RAND_MAX+1u) / N)
Все эти методы, очевидно, требуют знания RAND_MAX (который ANSI #defines в ) и предполагают, что N намного меньше, чем RAND_MAX. Когда N близко к RAND_MAX, и если диапазон случайного числа
генератор не кратен N (т.е. если (RAND_MAX + 1)% N! = 0), все
из этих методов выходят из строя: некоторые выходы происходят чаще, чем
другие. (Использование плавающей запятой не помогает; проблема в том, что rand
возвращает RAND_MAX + 1 различных значений, которые не всегда могут быть равномерно
разделить на N ведер.) Если это проблема, об единственном
Вы можете сделать это, чтобы вызвать rand несколько раз, отбрасывая определенные значения:
unsigned int x = (RAND_MAX + 1u) / N;
unsigned int y = x * N;
unsigned int r;
do {
r = rand();
} while(r >= y);
return r / x;
Для любого из этих методов легко сместить диапазон,
если необходимо; числа в диапазоне [M, N] могут быть сгенерированы с
что-то вроде
M + rand() / (RAND_MAX / (N - M + 1) + 1)
(Заметьте, кстати, что RAND_MAX является константой , сообщающей вам, что
фиксированный диапазон функции библиотеки C rand . Вы не можете установить RAND_MAX
к другому значению, и нет способа запросить rand
вернуть числа в другом диапазоне.)
Если вы начинаете с генератора случайных чисел, который возвращает
значения с плавающей точкой от 0 до 1 (например, последняя версия
PM и , о котором идет речь в вопросе 13.15 или drand48, о котором идет речь
13.21 ) все, что вам нужно сделать, чтобы получить целые числа от 0 до N-1, это
умножьте выходную мощность этого генератора на N:
(int)(drand48() * N)
Дополнительные ссылки
Ссылки: K & R2 Sec. 7.8.7 с. 168
PCS Sec. 11 стр. 172