2009-08-20 15 views
10

Dado el inicio y el final de un rango entero, ¿cómo puedo calcular un entero aleatorio distribuido normalmente entre este rango?¿Cómo se genera aleatoriamente distribuida normalmente desde un rango entero?

Me doy cuenta de que la distribución normal va - + infinito. Supongo que las colas pueden cortarse, así que cuando se calcule un azar fuera del rango, vuelva a calcular. Esto eleva la probabilidad de enteros en el rango, pero mientras este efecto sea tolerable (< 5%), está bien.

public class Gaussian 
{ 
    private static bool uselast = true; 
    private static double next_gaussian = 0.0; 
    private static Random random = new Random(); 

    public static double BoxMuller() 
    { 
     if (uselast) 
     { 
      uselast = false; 
      return next_gaussian; 
     } 
     else 
     { 
      double v1, v2, s; 
      do 
      { 
       v1 = 2.0 * random.NextDouble() - 1.0; 
       v2 = 2.0 * random.NextDouble() - 1.0; 
       s = v1 * v1 + v2 * v2; 
      } while (s >= 1.0 || s == 0); 

      s = System.Math.Sqrt((-2.0 * System.Math.Log(s))/s); 

      next_gaussian = v2 * s; 
      uselast = true; 
      return v1 * s; 
     } 
    } 

    public static double BoxMuller(double mean, double standard_deviation) 
    { 
     return mean + BoxMuller() * standard_deviation; 
    } 

    public static int Next(int min, int max) 
    { 
     return (int)BoxMuller(min + (max - min)/2.0, 1.0); 
    } 
} 

Probablemente necesite escalar la desviación estándar de alguna forma relativa al rango, pero no entiendo cómo.

Respuesta:

// Will approximitely give a random gaussian integer between min and max so that min and max are at 
    // 3.5 deviations from the mean (half-way of min and max). 
    public static int Next(int min, int max) 
    { 
     double deviations = 3.5; 
     int r; 
     while ((r = (int)BoxMuller(min + (max - min)/2.0, (max - min)/2.0/deviations)) > max || r < min) 
     { 
     } 

     return r; 
    } 

Respuesta

6

Si el método de Box-Muller devuelve una distribución normal "estándar", que tendrá media 0 y desviación estándar 1. Para transformar una distribución normal estándar, se multiplica el número al azar por X para obtener la desviación estándar X, y se agrega Y para obtener Y promedio, si la memoria me sirve correctamente.

Consulte el Wikipedia article's section on normalizing standard normal variables (property 1) para obtener una prueba más formal.


En respuesta a su comentario, la regla general es que el 99,7% de una distribución normal será de +/- 3 veces la desviación estándar. Si necesita una distribución normal de 0 a 100, por ejemplo, su media será la mitad, y su SD será (100/2)/3 = 16.667. Así que cualquiera que sea el valor que obtenga de su algoritmo Box-Muller, multiplique por 16.667 para "estirar" la distribución, luego sume 50 para "centrarla".


Juan, en respuesta a su comentario mas nuevo, realmente no estoy seguro de lo que es el punto de la función Next. Siempre usa una desviación estándar de 1 y una media de la mitad entre su mínimo y máximo.

Si quiere una media de Y, con ~ 99,7% de los números en el rango -X a + X, entonces simplemente llama al BoxMuller(Y, X/3).

+0

Sí, esto es lo que el BoxMuller (double mean, double standard_deviation) logra arriba. El problema, sin embargo, es que Next (int min, int max) devuelve valores muy cercanos a la mitad del rango. Esto es porque no entiendo cómo "escalar" la desviación correctamente. –

+0

Entonces, para 3.5 desviaciones estándar, sería "return (int) BoxMuller (min + (max - min)/2.0, (max - min)/2.0/3.5);"? –

+0

¿Puedo comentar que +/- 3 veces la desviación estándar no le da el 97% sino el 99.7%? +/- sigma: ~ 68% +/- 2sigma: ~ 95% +/- 3sigma: ~ 99.7% http://en.wikipedia.org/wiki/68-95-99.7_rule – DmitryK

1

Bueno, el -2 * sigma .. + 2 * sigma le dará el 95% de la curva de campana. (verifique la sección "Desviación estándar e intervalos de confianza" en el artículo wiki mencionado anteriormente).

Así modificar esta pieza:

return (int)BoxMuller(min + (max - min)/2.0, 1.0); 

y cambiar 1,0 (desviación estándar) a 2,0 (o incluso más si desea la cobertura de más del 95%)

return (int)BoxMuller(min + (max - min)/2.0, 2.0); 
+0

Ahora entiendo lo que quiero formular gracias a ti .. Quiero que sigan -2 * sigma .. + 2 * sigma al principio y al final del rango (mínimo, máximo) respectivamente. –

+0

Ah, lo entiendo ahora. Así que quiere salir de su valor medio de izquierda a derecha y "acertar", ya sea mínimo o máximo con un 95% de confianza. En este caso, mantienes tu media tal como la tienes (min + (max-min)/2), pero necesitas calcular tu sigma (desviación estándar). Salir por 2 * sigma nos da ese intervalo de 95%. Entonces, la duración de este intervalo es 4 * sigma. Pero también podemos calcularlo como (máximo-mínimo). Lo que nos da sigma = (max-min)/4. ¿Puedes intentarlo? – DmitryK

+0

"golpear" dentro del rango min..max con el 95% de confianza, solo para ser precisos en mi redacción. – DmitryK

Cuestiones relacionadas