Генератор Псевдослучайных Чисел-Экспоненциальное Распределение
Я хотел бы создать некоторые псевдослучайные числа, и до сих пор я был очень доволен библиотекой .Net . PRNGs этого разнообразия должно использовать равномерное распределение, но я бы очень хотел сгенерировать некоторые числа с помощью Экспоненциальное Распределение.
я программирую на C#, хотя я буду принимать псевдокод или C++, Java или тому подобное.
предложения / код фрагменты / алгоритмы / мысли?
7 ответов:
поскольку у вас есть доступ к генератору однородных случайных чисел, генерируя случайное число, распределенное с другим распределением, CDF которого вы знаете, легко использовать метод инверсии.
Итак, сгенерируйте однородное случайное число,
u
, в[0,1)
, затем вычислитьx
by:
x = log(1-u)/(
-λ)
,где λ-параметр скорости экспоненциального распределения. Теперь,
x
- случайное число с экспоненциальным распределением. Обратите внимание, чтоlog
вышеln
, натурального логарифма.
фундаментальная Теорема выборки гласит, что если вы можете нормализовать, интегрировать и инвертировать желаемое распределение, вы свободны от дома.
если у вас есть нужные рассылки
F(x)
нормированы на[a,b]
. Вы вычисляетеC(y) = \int_a^y F(x) dx
инвертировать, чтобы получить
C^{-1}
, кинутьz
равномерно на [0,1) и найтиx_i = C^{-1}(z_i)
который будет иметь желаемое распределение.
в вашем случае:
F(x) = ke^{-kx}
и я буду считать, что вы хочу!--9-->. Получаем:C(y) = 1 - e^{-ky}
который можно инвертировать, чтобы дать
x = -1/k ln(1 - z)
для z бросается равномерно на
[0,1)
.
но, честно говоря, использование хорошо отлаженной библиотеки умнее, если вы не делаете это для собственного назидания.
Если вы хотите хорошие случайные числа, рассмотрите возможность подключения к подпрограммам gsl:http://www.gnu.org/software/gsl/. у них есть рутина
gsl_ran_exponential
. Если вы хотите генерировать случайные числа с помощью встроенного генератора с равномерным распределением на [0, 1) (например, u=Random.Далее(0, N-1)/N, для некоторых больших N), то просто используйте:-mu * log (1-u)
см. randist / exponential.c в источнике gsl.
EDIT: просто для сравнения с некоторыми более поздними ответами-это эквивалентно mu = 1/лямбда. mu здесь-среднее значение распределения, также называемое параметром масштаба на странице Википедии, с которой связан OP, а лямбда-параметр скорости.
одно интересное свойство экспоненциального распределения: рассмотрим процесс прибытия с экспоненциальными межчастичными временами. Возьмите любой период времени (t1, t2) и прибытия в этот период. Эти поступления равномерно распределены между t1 и t2. (Шелдон Росс, Стохастические Процессы).
Если у меня есть генератор псевдослучайных чисел и по какой-то причине (например, мое программное обеспечение не может вычислять журналы), вы не хотите выполнять приведенное выше преобразование, но хотите экспоненциальный r.v. со средним значением 1,0.
вы можете :
1) Создать 1001 U (0,1) случайных величин.
2) сортировка по порядку
3) вычесть второе из первого, третье из второго,... чтобы получить 1000 различий.
4) эти различия являются экспоненциальными RVs с распределением со средним = 1.0.
менее эффективно, я думаю, но средство для той же цели.
С открытым исходным кодом библиотека по математике необычные Дэн Дайер предоставляет генераторы случайных чисел, распределения вероятностей, комбинаторику и статистику для Java.
среди других ценных классов,
ExponentialGenerator
по существу реализовал идею, объясненную @Alok Singhal. В его учебник блог, фрагмент кода приведен для моделирования случайного события, которое произошло в среднем 10 раз в минуту:final long oneMinute = 60000; Random rng = new MersenneTwisterRNG(); // Generate events at an average rate of 10 per minute. ExponentialGenerator gen = new ExponentialGenerator(10, rng); boolean running = true; while (true) { long interval = Math.round(gen.nextValue() * oneMinute); Thread.sleep(interval); // Fire event here. }
конечно, если вы предпочитаете единица времени
per second
(вместоa minute
здесь), вам просто нужно установитьfinal long oneMinute = 1000
.углубляясь в исходный код методом
nextValue()
наExponentialGenerator
, вы найдете так называемые обратное преобразование выборки описано в Generating_exponential_variates [wiki]:public Double nextValue() { double u; do { // Get a uniformly-distributed random double between // zero (inclusive) and 1 (exclusive) u = rng.nextDouble(); } while (u == 0d); // Reject zero, u must be positive for this to work. return (-Math.log(u)) / rate.nextValue(); }
П. С.: в последнее время я использую необычные библиотеки математике. Спасибо Дэн Дайер.
Если я понимаю вашу проблему, и вы можете принять конечное число PRNG, вы можете следовать такому подходу, как:
- создайте массив, где каждый элемент находится в вашем экспоненциальном распределении
- сгенерируйте PRNG, который является целочисленным индексом в массиве. Возвращает элемент в массиве по этому индексу.
Это было то, что я использовал, когда сталкивался с подобными требования:
// sorry.. pseudocode, mine was in Tcl: int weighted_random (int max) { float random_number = rand(); return floor(max - ceil( max * random_number * random_number)) }
конечно, это формула возведения в квадрат случайного числа, поэтому вы генерируете случайное число вдоль квадратичной кривой.