Pregunta

Dado el inicio y el final de un rango entero, ¿cómo calculo un entero aleatorio distribuido normalmente entre este rango?

Me doy cuenta de que la distribución normal entra en -+ infinito. Supongo que las colas se pueden cortar, por lo que cuando un aleatorio se calcula fuera del rango, recomputa. Esto eleva la probabilidad de enteros en el rango, pero mientras el 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 manera en relación con el rango, pero no entiendo cómo.

Responder:

    // 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;
    }
¿Fue útil?

Solución

Si el método de mululador de caja devuelve una distribución normal "estándar", tendrá una desviación significa 0 y estándar 1. Para transformar una distribución normal estándar, multiplica su número aleatorio por x para obtener la desviación estándar x, y agrega y para obtener significa Y, si la memoria me sirve correctamente.

Ver el Sección del artículo de Wikipedia sobre la normalización de las variables normales estándar (propiedad 1) para una prueba más formal.


En respuesta a su comentario, la regla general es que el 99.7% de una distribución normal estará dentro de +/- 3 veces la desviación estándar. Si necesita una distribución normal de 0 a 100, por ejemplo, su media será a mitad de camino, y su SD será (100/2)/3 = 16.667. Entonces, cualquiera de los valores que obtenga de su algoritmo de mululador de caja, multiplique por 16.667 para "estirar" de la distribución, luego agregue 50 a "centrarse".


John, en respuesta a tu nuevo comentario, realmente no estoy seguro de cuál es el punto de la Next función. Siempre utiliza una desviación estándar de 1 y una media de medio camino entre su Min y Max.

Si quieres una media de y, con ~ 99.7% de los números en el rango -x a +x, entonces solo llamas BoxMuller(Y, X/3).

Otros consejos

Bueno, el -2*Sigma ..+2*Sigma te 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 ya mencionado).

Entonces modifique 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 más del 95% de cobertura)

return (int)BoxMuller(min + (max - min) / 2.0, 2.0);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top