Генератор Псевдослучайных Чисел-Экспоненциальное Распределение


Я хотел бы создать некоторые псевдослучайные числа, и до сих пор я был очень доволен библиотекой .Net . PRNGs этого разнообразия должно использовать равномерное распределение, но я бы очень хотел сгенерировать некоторые числа с помощью Экспоненциальное Распределение.

я программирую на C#, хотя я буду принимать псевдокод или C++, Java или тому подобное.

предложения / код фрагменты / алгоритмы / мысли?

7 53

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))
}

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