Итак, нам нужно следующее распределение, от наименее вероятного к наиболее вероятному:
*
**
***
****
*****
и т.д.
Давайте попробуем сопоставить равномерно распределенную целочисленную случайную переменную с этим распределением:
1
2 3
4 5 6
7 8 9 10
11 12 13 14 15
и т.д.
Таким образом, если мы сгенерируем равномерно распределенное случайное целое число от 1 до, скажем, 15, в данном случае для K = 5
, нам просто нужно выяснить, к какой корзине он подходит. Самое сложное в том, как это сделать.
Обратите внимание, что числа справа - это треугольные числа! Это означает, что для случайно сгенерированного X
от 1
до T_n
нам просто нужно найти N
такой, что T_(n-1) < X <= T_n
. К счастью, существует четко определенная формула для нахождения «треугольного корня» данного числа , которую мы можем использовать в качестве основы нашего отображения от равномерного распределения до сегмента:
// Assume k is given, via parameter or otherwise
int k;
// Assume also that r has already been initialized as a valid Random instance
Random r = new Random();
// First, generate a number from 1 to T_k
int triangularK = k * (k + 1) / 2;
int x = r.nextInt(triangularK) + 1;
// Next, figure out which bucket x fits into, bounded by
// triangular numbers by taking the triangular root
// We're dealing strictly with positive integers, so we can
// safely ignore the - part of the +/- in the triangular root equation
double triangularRoot = (Math.sqrt(8 * x + 1) - 1) / 2;
int bucket = (int) Math.ceil(triangularRoot);
// Buckets start at 1 as the least likely; we want k to be the least likely
int n = k - bucket + 1;
n
теперь должно иметь указанное распределение.