65 votes

Générateur de nombres pseudo-aléatoires - Distribution exponentielle

Je voudrais générer des nombres pseudo-aléatoires, et jusqu'à maintenant, j'ai été très content de la .Net de la bibliothèque de l' Random.Next(int min, int max) fonction. PRNGs de cette variété sont censés être à l'aide d'une distribution Uniforme, mais j'aimerais beaucoup pour générer des nombres à l'aide d'une Distribution Exponentielle.

Je suis à la programmation en C#, bien que je vais accepter de pseudo ou C++, Java ou autre.

Toutes les suggestions / extraits de code / algorithmes / pensées?

112voto

Alok Singhal Points 33073

Puisque vous avez accès à l'instauration d'un générateur de nombre aléatoire, de la génération d'un nombre aléatoire distribué avec d'autres de distribution dont la CDF vous savez c'est facile à l'aide de la méthode d'inversion.

Donc, de générer un nombre aléatoire uniforme, u, en [0,1), puis de calculer x par:

x = log(1-u)/(−λ),

où λ est le taux de paramètre de la distribution exponentielle. Maintenant, x est un nombre aléatoire avec une distribution exponentielle. Notez que log ci-dessus est - ln, le logarithme naturel.

16voto

dmckee Points 50318

Le Théorème Fondamental de l'Échantillonnage dit que si vous pouvez normaliser, d'intégrer et d'inverser la distribution désirée vous êtes à la maison gratuitement.

Si vous avez une distribution désirée F(x) normalisés à l' [a,b]. Vous calculez

C(y) = \int_a^y F(x) dx

inverser que pour obtenir de l' C^{-1}, jeter z de manière uniforme sur [0,1) et de trouver

x_i = C^{-1}(z_i)

qui aura la distribution désirée.


Dans votre cas: F(x) = ke^{-kx} et je suppose que vous souhaitez [0,infinity]. Nous obtenons :

C(y) = 1 - e^{-ky}

qui est invertable à donner

x = -1/k  ln(1 - z)

pour z jeté uniformément sur [0,1).


Mais, franchement, à l'aide d'un bien de débogage de la bibliothèque est plus intelligent si vous ne le faites pour votre propre édification.

7voto

Ramashalanka Points 5481

Si vous voulez de bons nombres aléatoires, poser un lien vers la gsl routines: http://www.gnu.org/software/gsl/. Ils ont la routine gsl_ran_exponential. Si vous voulez générer des nombres aléatoires l'aide d'un générateur avec une distribution uniforme sur [0, 1) (par exemple, u=Random.Prochaine(0, N-1)/N, pour certains, un grand N), alors il suffit d'utiliser:

-mu * log (1-u)

Voir randist/exponentielle.c dans la gsl source.

EDIT: juste pour la comparaison avec d'autres plus tard réponses - c'est l'équivalent avec mu = 1/lambda. mu ici est la moyenne de la distribution, aussi appelé le paramètre d'échelle sur la page wikipedia de l'OP liés à, et le lambda est le paramètre vitesse.

4voto

Grembo Points 997

Une propriété intéressante de la distribution exponentielle: Considérons un processus d'arrivée avec exponentielle interarrival fois. Prendre une période de temps (t1, t2) et les arrivées dans cette période. Les arrivées sont UNIFORMÉMENT distribués entre t1 et t2. (Sheldon Ross, Processus Stochastiques).

Si j'ai un générateur de nombres pseudo aléatoires et, pour une raison quelconque (par exemple, mon logiciel ne peut pas calculer les journaux) vous ne voulez pas faire la transformation ci-dessus, mais que vous voulez une exponentielle r.v. avec une moyenne de 1.0.

Vous pouvez :

1) Créer 1001 U(0,1) des variables aléatoires.

2) les Trier dans l'ordre

3) retirer le deuxième à partir de la première, troisième à partir de la deuxième,... pour obtenir 1000 différences.

4) Ces différences sont exponentielle des Caravanes à partir d'une distribution à moyenne = 1.0.

De moins en moins efficace, je pense, mais un moyen de parvenir à la même fin.

1voto

hengxin Points 235

L'open-source Uncommons Mathématiques de la bibliothèque par Dan Dyer fournit des générateurs de nombres aléatoires, distributions de probabilités, combinatoire et statistiques pour Java.

Parmi d'autres classes, ExponentialGenerator a essentiellement mis en œuvre l'idée expliqué par @Alok Singhal. Dans son tutoriel blog, un extrait de code est donné à simuler un événement aléatoire qui s'est passé en moyenne 10 fois par minute:

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

Bien sûr, si vous préférez l'unité de temps per second (au lieu de a minute ici), il vous suffit de définir final long oneMinute = 1000.

Pour aller plus loin dans le code source de la méthode de nextValue() de ExponentialGenerator,, vous trouverez la soi-disant transformation inverse d'échantillonnage décrites dans 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();
}  

P. S.: Récemment, je suis en utilisant le Uncommons Mathématiques de la bibliothèque. Merci Dan Dyer.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X