Взвешенное случайное число (без предопределенных значений!)

в настоящее время мне нужна функция, которая дает взвешенное случайное число. Он должен выбрать случайное число между двумя двойными/целыми числами (например, 4 и 8), в то время как значение в середине (6) будет встречаться в среднем примерно в два раза чаще, чем значения ограничителя 4 и 8. Если бы это были только целые числа , я мог бы предопределить значения с помощью переменных и пользовательских вероятностей, но мне нужно, чтобы функция давала двойное число как минимум с двумя цифрами (что означает тысячи разных чисел)!

Я использую среду "Game Maker", которая предоставляет все виды базовых генераторов случайных чисел, но не взвешенных.

Может ли кто-нибудь привести меня в правильном направлении, как этого добиться?

Заранее спасибо!


person DragonGamer    schedule 28.04.2015    source источник


Ответы (2)


Сумма двух независимых непрерывных униформ(0,1), U1 и U2, имеет непрерывное симметричное треугольное распределение между 0 и 2. Распределение имеет пик в 1 и сужается до нуля на обоих концах. Мы можем легко перевести это в диапазон (4,8) путем масштабирования на 2 и добавления 4, то есть 4 + 2*(U1 + U2).

Однако вам не нужна нулевая высота в конечных точках, вам нужна половина высоты пика. Другими словами, вам нужен треугольник, сидящий на прямоугольном основании (т. е. равномерный), с высотой h на концах и высотой 2h в середине. Это упрощает жизнь, потому что вершина треугольника должна быть высотой h над прямоугольным основанием, а треугольник высотой h имеет половину площади прямоугольника с тем же основанием и высотой h. Отсюда следует, что 2/3 вашей вероятности находится в основании, 1/3 – в треугольнике.

Объединение вышеперечисленных элементов приводит к следующему алгоритму псевдокода. Если rnd() — это вызов функции, который возвращает непрерывные однородные (0,1) случайные числа:

define makeValue()
   if rnd() <= 2/3    # Caution, may want to use 2.0/3.0 for many languages
      return 4 + (4 * rnd())
   else
      return 4 + (2 * (rnd() + rnd()))

Используя это, я выдал миллион значений и построил гистограмму:

Распределение в форме дома

person pjs    schedule 28.04.2015
comment
Большое спасибо! Интересная концепция и хорошо работает! - person DragonGamer; 29.04.2015
comment
@DragonGamer Я не могу претендовать на признание ни одной из частей. Суммирование случайных величин называется сверткой, сборка распределения из составных частей называется композицией. Оба метода хорошо известны в сообществе симуляторов. - person pjs; 30.04.2015

На случай, если кому-то понадобится это в Game Maker (или другом языке) как универсальная функция:

if random(1) <= argument0
   return argument1 + ((argument2-argument1) * random(1))
else
   return argument1 + (((argument2-argument1)/2) * (random(1) + random(1)))

Вызывается следующим образом (аналогично стандартной функции random_range):

val = weight_random_range(FACTOR, FROM, TO)

«ФАКТОР» определяет, какая часть всей цифры вероятности является «базой» для постоянной вероятности. Например. 2/3 для рисунка выше. 0 обеспечит идеальный треугольник, а 1 — прямоугольник (без взвешивания).

person DragonGamer    schedule 29.04.2015