Все ответы пока математически неверны. Возврат rand() % N
не дает единообразного числа в диапазоне, [0, N)
если не N
делит длину интервала, на который rand()
выполняется возврат (т.е. является степенью 2). Более того, никто не знает, независимы ли модули rand()
: возможно, что они идут 0, 1, 2, ...
, что равномерно, но не очень случайно. Единственное предположение, которое кажется разумным, состоит в том rand()
, что выводится распределение Пуассона: любые два неперекрывающихся подинтервала одинакового размера одинаково вероятны и независимы. Для конечного набора значений это подразумевает равномерное распределение, а также гарантирует, что значения rand()
хорошо разбросаны.
Это означает, что единственный правильный способ изменить диапазон rand()
- разделить его на блоки; например, если RAND_MAX == 11
вам нужен диапазон 1..6
, вам следует присвоить {0,1}
1, {2,3}
2 и так далее. Это непересекающиеся интервалы одинакового размера, поэтому они распределены равномерно и независимо.
Предложение использовать деление с плавающей запятой математически правдоподобно, но в принципе страдает проблемами округления. Возможно, double
это достаточно высокая точность, чтобы заставить его работать; возможно нет. Я не знаю и не хочу разбираться в этом; в любом случае ответ зависит от системы.
Правильный способ - использовать целочисленную арифметику. То есть вам нужно что-то вроде следующего:
#include <stdlib.h> // For random(), RAND_MAX
// Assumes 0 <= max <= RAND_MAX
// Returns in the closed interval [0, max]
long random_at_most(long max) {
unsigned long
// max <= RAND_MAX < ULONG_MAX, so this is okay.
num_bins = (unsigned long) max + 1,
num_rand = (unsigned long) RAND_MAX + 1,
bin_size = num_rand / num_bins,
defect = num_rand % num_bins;
long x;
do {
x = random();
}
// This is carefully written not to overflow
while (num_rand - defect <= (unsigned long)x);
// Truncated division is intentional
return x/bin_size;
}
Петля необходима для получения идеально равномерного распределения. Например, если вам заданы случайные числа от 0 до 2, а вам нужны только числа от 0 до 1, вы просто продолжаете тянуть, пока не получите 2; нетрудно проверить, что это дает 0 или 1 с равной вероятностью. Этот метод также описан в ссылке, приведенной в ответе №№, но с другим кодом. Я использую, random()
а не rand()
потому, что он имеет лучшее распределение (как указано на странице руководства для rand()
).
Если вы хотите получить случайные значения за пределами диапазона по умолчанию [0, RAND_MAX]
, вам придется сделать что-то сложное. Пожалуй, наиболее целесообразным является определить функцию , random_extended()
которая тянет n
бит ( с использованием random_at_most()
) и возвращается в [0, 2**n)
, а затем применить random_at_most()
с random_extended()
вместо random()
(и 2**n - 1
вместо RAND_MAX
) , чтобы тянуть случайное значение меньше 2**n
, если у вас есть числовой тип , который может содержать такие ценность. Наконец, конечно, вы можете получать значения при [min, max]
использовании min + random_at_most(max - min)
, включая отрицательные значения.