Все ответы до сих пор математически неверны. Возвращение 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 с равной вероятностью. Этот метод также описан в ссылке, которую nos дал в своем ответе, хотя кодируется по-другому. Я использую 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)
, включая отрицательные значения.