49

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) de la biblioteca .Net. Los PRNG de esta variedad son supuestos para usar un Uniform distribution, pero me gustaría generar algunos números usando un Exponential Distribution.Generador de números pseudoaleatorios - Distribución exponencial

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

Cualquier sugerencia/fragmento de código/algoritmo/pensamientos?

+0

http://stackoverflow.com/questions/918736/random-number-generator-that-produces-a-power-law-distribution no es exactamente un duplicado, pero solo porque la distribución deseada es diferente. Tiene la respuesta correcta ... – dmckee

+1

http://ftp.arl.mil/random/random.pdf es una colección de algoritmos que implementan varias distribuciones de probabilidad, incluida Exp. – mdup

Respuesta

83

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 cuyo CDF conoce es fácil usando el inversion method.

Por lo tanto, generar un número aleatorio uniforme, u, en [0,1), a continuación, calcular x por:

x = log(1-u)/( − y lambda; ),

where & lambda; 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 log arriba es ln, el logaritmo natural.

+1

Sí ... esto es lo que necesitaba. Después de leer la página de wikipedia más de cerca, el método de inversión tiene mucho sentido. Para otros que leen su respuesta, puede haber cierta confusión sobre la base de su función de registro. Técnicamente, debería ser base e, es decir, ln(). –

+0

Sí, mi 'log' es el registro natural, aunque cualquier base servirá, solo que con una lambda diferente :-). –

+4

1-u para ti [0,1) es igual a (0,1]. Así que puedes hacer simplemente log ((0,1))/(- λ) – varela

0

Si entiendo su problema, y ​​se puede aceptar un número finito de PRNG, podría seguir un enfoque como:

  • Crear una matriz en donde cada elemento está en su distribución exponencial
  • Generar un PRNG que es un índice entero en la matriz. Devuelve el elemento en la matriz en ese índice.
+0

Este método aproximado funciona para casos difíciles, pero no es necesario este tiempo de espera. Una distribución exponencial puede ser arrojada exactamente. – dmckee

+0

¿Por qué el voto a favor? – GreenMatt

-2

Esto era lo que hacía cuando se enfrentan 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 la cuadratura del número al azar por lo que está generando un número aleatorio a lo largo de una curva cuadrática.

+0

Obtiene la distribución incorrecta. – dmckee

+0

Sí. Originalmente tuve ** "Siéntase libre de sustituir con la fórmula adecuada" ** al final que se eliminó accidentalmente durante una edición. La idea era dar una idea de cómo hacer esto luego google/leer cuál sería la fórmula adecuada \ *. No estoy reeditando la respuesta porque de lo contrario este comentario no tendría sentido. Solo lea este comentario antes de votar abajo. – slebetman

6

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.

12

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].A calcular

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

invertido que para conseguir C^{-1}, lanzar z de manera uniforme en [0,1) y encontrar

x_i = C^{-1}(z_i) 

que tendrá la distribución deseada.


En su caso: F(x) = ke^{-kx} y voy a suponer que usted quiere [0,infinity]. Obtenemos:

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

que es invertible en hacerle

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

para z arrojados de manera uniforme sobre [0,1).


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

+0

Respuesta completa, gracias. –

4

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 pseudoaleatorio y, por algún motivo (por ejemplo, mi software no puede calcular los registros), no desea realizar la transformación anterior, pero desea una r.v exponencial. con una media de 1.0.

Puede:

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

2) Ordenar

3) Restar la segunda de la primera, tercera de la segunda, ... para conseguir 1000 diferencias.

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

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

+0

Interesante idea. ¿Cómo controlo el valor de λ? –

+0

Oh - Dije mal el proceso un poco. De hecho, creé 1001 rv en el intervalo (0,1000) y tomé 1000 diferencias. El resultado es exponencial con una media de 1.0 ya que la diferencia promedio es 1.0. Para obtener otro significado, simplemente multiplique la diferencia por el medio que desee. Por cierto, verifiqué los resultados en @Risk para asegurarme de que la distribución fuera exponencial con una media de 1.0. – Grembo

1

La fuente abierta Uncommons Maths library by Dan Dyer proporciona generadores de números aleatorios, distribuciones de probabilidad, combinatoria y estadísticas para Java.

Entre otras clases valiosas, ExponentialGenerator básicamente ha implementado la idea explicada por @Alok Singhal. En its tutorial blog, se le da un fragmento de código para simular un evento aleatorio que ha pasado una media de 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 usted prefiere la unidad de tiempo per second (en lugar de a minute aquí), sólo tiene para establecer final long oneMinute = 1000.

Profundizando en el source code del método nextValue() de ExponentialGenerator, se encuentra el llamado transformada inversa de muestreo se describe 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(); 
} 

PS: Recientemente estoy usando el Uncommons Matemáticas biblioteca. Gracias Dan Dyer.

Cuestiones relacionadas