Domanda

Dato l'inizio e la fine di un intervallo di numeri interi, come faccio a calcolare un intero casuale normalmente distribuito tra questo intervallo?

Mi rendo conto che la distribuzione normale va in - + infinito. Credo che le code possono essere di taglio, in modo che quando un casuale ottiene calcolato fuori del campo, recompute. Questo eleva la probabilità di numeri interi nella gamma, ma finché il questo effetto è tollerabile (<5%), va bene.

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); 
    }
}

Probabilmente ho bisogno di scalare la deviazione standard in qualche modo rispetto alla gamma, ma non capisco come.

Risposta:

    // 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;
    }
È stato utile?

Soluzione

Se il metodo di Box-Muller restituisce un "standard" distribuzione normale, avrà media 0 e deviazione standard 1. Per trasformare una distribuzione normale standard, si moltiplica il tuo numero a caso da X per ottenere deviazione standard X, e si aggiunge Y per ottenere media Y, se la memoria non mi inganna.

Vedere la sezione di voci di Wikipedia che la normalizzazione delle variabili normale standard (di proprietà 1) per un più la prova formale.


In risposta al tuo commento, la regola generale è che il 99,7% di una distribuzione normale sarà entro +/- 3 volte la deviazione standard. Se avete bisogno di una distribuzione normale da 0 a 100, per esempio, che il vostro media sarà a metà strada, e la vostra SD sarà (100/2) / 3 = 16.667. Quindi, qualunque cosa i valori si ottiene dal vostro algoritmo di Box-Muller, moltiplicare per 16,667 per "allungare" la distribuzione fuori, quindi aggiungere 50 al "centro" di esso.


John, in risposta al vostro ultimo commento, sono davvero non sono sicuro che è il punto della funzione Next. Esso utilizza sempre una deviazione standard pari a 1 e una media di a metà strada tra il minimo e massimo.

Se si vuole una media di Y, con ~ 99,7% dei numeri nella gamma -X e + X, poi basta chiamare BoxMuller(Y, X/3).

Altri suggerimenti

Bene, il -2 * Sigma .. + 2 * sigma vi darà il 95% della curva a campana. (Controllare la sezione "Standard intervalli di deviazione e di confidenza" in questo articolo wiki già citato).

Quindi modificare questo pezzo:

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

e cambiare 1,0 (deviazione standard) a 2,0 (o anche di più se si desidera una copertura superiore al 95%)

return (int)BoxMuller(min + (max - min) / 2.0, 2.0);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top