Generador de números pseudoaleatorios – Distribución exponencial

Me gustaría generar algunos números pseudoaleatorios y hasta ahora he estado muy contento con la función Random.Next(int min, int max) la biblioteca .Net. Se supone que los PRNG de esta variedad usan una distribución Uniforme , pero me gustaría generar algunos números usando una Distribución Exponencial .

Estoy progtwigndo en C #, aunque aceptaré pseudocódigo o C ++, Java o similares.

¿Alguna sugerencia / fragmento de código / algoritmo / pensamiento?

Dado que tiene acceso a un generador de números aleatorios uniforme, la generación de un número aleatorio distribuido con otra distribución cuya CDF conoce es fácil utilizando el método de inversión .

Entonces, genere un número aleatorio uniforme, u , en [0,1) , luego calcule x por:

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

donde λ es el parámetro de velocidad de la distribución exponencial. Ahora, x es un número aleatorio con una distribución exponencial. Tenga en cuenta que el log anterior es ln , el logaritmo natural.

El Teorema Fundamental del Muestreo sostiene que si puedes normalizar, integrar e invertir la distribución deseada, estarás en casa libre.

Si tiene una distribución deseada F(x) normalizada en [a,b] . Usted calcula

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

invierta eso para obtener C^{-1} , lance z uniformemente en [0,1) y encuentre

 x_i = C^{-1}(z_i) 

que tendrá la distribución deseada.


En tu caso: F(x) = ke^{-kx} y supondré que quieres [0,infinity] . Obtenemos :

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

que es invegable para dar

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

para z arrojado uniformemente en [0,1) .


Pero, francamente, usar una biblioteca bien depurada es más inteligente a menos que esté haciendo esto para su propia edificación.

Si quieres buenos números aleatorios, considera vincular a las rutinas gsl: http://www.gnu.org/software/gsl/ . Tienen la rutina gsl_ran_exponential . Si desea generar números aleatorios utilizando un generador incorporado con una distribución uniforme en [0, 1) (por ej., U = Aleatorio.Next (0, N-1) / N, para una N grande), simplemente use:

 -mu * log (1-u) 

Ver randist / exponential.c en la fuente gsl.

EDITAR: solo para comparar con algunas respuestas posteriores, esto es equivalente con mu = 1 / lambda. mu aquí está la media de la distribución, también llamada parámetro de escala en la página de wikipedia a la que se vincula el OP, y lambda es el parámetro de velocidad.

Una propiedad interesante de la distribución exponencial: Considere un proceso de llegada con tiempos de conexión exponenciales. Tome cualquier período de tiempo (t1, t2) y las llegadas en ese período. Esas llegadas se distribuyen UNIFORMEMENTE entre t1 y t2. (Sheldon Ross, procesos estocásticos).

Si tengo un generador de números pseudoaleatorios y, por algún motivo (por ejemplo, mi software no puede calcular los registros), no desea realizar la transformación anterior, sino que desea una rv exponencial con una media de 1.0.

Usted puede :

1) Cree 1001 U (0,1) variables aleatorias.

2) Ordenar por orden

3) Reste el segundo del primero, el tercero del segundo, … para obtener 1000 diferencias.

4) Esas diferencias son RVs exponenciales con una distribución con media = 1.0.

Menos eficiente, creo, pero un medio para el mismo fin.

La biblioteca de código abierto Uncommons Maths de Dan Dyer proporciona generadores de números aleatorios, distribuciones de probabilidad, combinatoria y estadísticas para Java.

Entre otras clases valiosas, ExponentialGenerator esencialmente ha implementado la idea explicada por @Alok Singhal. En su blog tutorial , se da un fragmento de código para simular algún evento aleatorio que ocurrió en promedio 10 veces por minuto:

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

Por supuesto, si prefiere la unidad de tiempo per second (en lugar de a minute aquí), solo necesita establecer el valor final long oneMinute = 1000 .

Profundizando en el código fuente del método nextValue() de ExponentialGenerator , encontrará el denominado muestreo de transformación inversa descrito en 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(); } 

PD: Recientemente estoy usando la biblioteca Uncommons Maths. Gracias Dan Dyer.

Si entiendo su problema y puede aceptar un número finito de PRNG, puede seguir un enfoque como:

  • Crea una matriz donde cada elemento está en tu distribución exponencial
  • Genere un PRNG que es un índice entero en la matriz. Devuelve el elemento en la matriz en ese índice.

Esto fue lo que usé cuando me enfrenté a requisitos similares:

 // sorry.. pseudocode, mine was in Tcl: int weighted_random (int max) { float random_number = rand(); return floor(max - ceil( max * random_number * random_number)) } 

Por supuesto, esta es la fórmula de cuadrar el número aleatorio, por lo que está generando un número aleatorio a lo largo de una curva cuadrática.