В подобных ситуациях вам не нужно вызывать генератор случайных чисел более одного раза. Все, что вам нужно, это таблица совокупных вероятностей:
double c[k] = // the probability that X <= k (k = 0,...)
Затем сгенерируйте случайное число 0 <= r < 1
и возьмите первое целое число X
, такое что c[X] > r
. Вы можете найти это X
с помощью двоичного поиска.
Чтобы сгенерировать эту таблицу, нам нужны индивидуальные вероятности
p[k] = lambda^k / (k! e^lambda) // // the probability that X = k
Если lambda
велико, это становится крайне неточным, как вы уже нашли. Но мы можем использовать хитрость здесь: начать с (или около) наибольшего значения, с k = floor[lambda]
, и притвориться на момент, что p[k]
равно 1
. Затем вычислите p[i]
для i > k
, используя рекуррентное соотношение
p[i+1] = (p[i]*lambda) / (i+1)
и для i < k
с использованием
p[i-1] = (p[i]*i)/lambda
Это гарантирует, что самые большие вероятности имеют максимально возможную точность.
Теперь просто вычислите c[i]
, используя c[i+1] = c[i] + p[i+1]
, до точки, где c[i+1]
совпадает с c[i]
. Затем вы можете нормализовать массив путем деления на это предельное значение c[i]
; или вы можете оставить массив как есть, и использовать случайное число 0 <= r < c[i]
.
См .: http://en.wikipedia.org/wiki/Inverse_transform_sampling