Я хочу генерировать случайные числа с диапазоном (n к m, например, 100 - 150), но вместо чисто случайного я хочу, чтобы результаты были основаны на нормальном распределении.
Этим я подразумеваю, что в целом хочу числа, "кластеризируемые" приблизительно 125.
Я нашел этот пакет случайного числа, который, кажется, имеет многое из того, в чем я нуждаюсь: http://codeproject.com/KB/recipes/Random.aspx
Это поддерживает множество случайных генераторов (включайте mersiene обманщика), и может применить генератор к распределению.
Но я смущен, если я использую генератор нормального распределения, случайные числа примерно от-6 до +8 (по-видимому, истинный диапазон является float.min к float.max).
Как делают масштаб это к моему необходимому диапазону?
Стандартное нормальное распределение имеет среднее 0 и стандартное отклонение 1; если вы хотите получить распределение со средним m
и отклонением s
, просто умножьте на s
, а затем добавьте m
. Поскольку нормальное распределение теоретически бесконечно, вы не можете установить жесткий предел диапазона, например (от 100 до 150), не отвергая явно числа, выходящие за его пределы, но при соответствующем выборе отклонения вы можете быть уверены, что (например) 99% ваших чисел будут находиться в пределах диапазона.
Около 99,7% популяции находится в пределах +/- 3 стандартных отклонений, поэтому если вы выберете отклонение около (25/3)
, это должно сработать хорошо.
Итак, вам нужно что-то вроде: (normal * 8.333) + 125
Ответ tzaman правильный, но при использовании библиотеки, которую вы связали, есть более простой способ, чем выполнять вычисления самостоятельно: Объект NormalDistribution
имеет записываемые свойства Mu
(означает среднее значение) и Sigma
(стандартное отклонение). Итак, следуя числам tzaman, установите Mu
равным 125 и Sigma
равным 8.333.
Ради интереса, довольно просто генерировать нормально распределенные случайные числа из равномерного ГПСЧ (хотя это нужно делать попарно):
Random rng = new Random();
double r = Math.Sqrt(-2 * Math.Log(rng.NextDouble()));
double θ = 2 * Math.Pi * rng.NextDouble();
double x = r * Math.Cos(θ);
double y = r * Math.Sin(θ);
x
и y
теперь содержат два независимых, нормально распределенных случайных числа со средним 0 и дисперсией 1. Вы можете масштабировать и переводить их по мере необходимости, чтобы получить нужный вам диапазон (как объясняет interjay).
Пояснение:
Этот метод называется преобразованием Бокса-Маллера. Он использует свойство двумерного единичного гаусса, что само значение плотности, p = exp(-r^2/2)
, равномерно распределено между 0
и 1
(константа нормировки для простоты удалена).
Поскольку такое значение можно легко сгенерировать с помощью равномерного ГПСЧ, в итоге получается круговой контур радиуса r = sqrt(-2 * log(p))
. Затем вы можете сгенерировать вторую равномерную случайную величину между 0
и 2*pi
, чтобы получить угол θ
, который определяет уникальную точку на вашем круговом контуре. Наконец, вы можете сгенерировать две i.i.d. нормальные случайные величины, преобразовав полярные координаты (r, θ)
обратно в картезианские координаты (x, y)
.
Это свойство - то, что p
равномерно распределено - не выполняется для других размерностей, вот почему вы должны генерировать ровно две нормальные переменные за раз.
Это может быть слишком упрощенно для ваших нужд, но быстрый и дешевый способ получить случайное число с распределением, взвешенным к центру, - это просто добавить 2 (или более) случайных числа.
Подумайте, когда вы бросаете два шестигранных кубика и складываете их. Чаще всего получается 7, затем 6 и 8, затем 5 и 9 и т. Д. И лишь изредка 2 или 12.