Question

Compte tenu du début et de la fin d'une gamme entière, comment calculer un entier aléatoire normalement distribué entre cette gamme?

Je me rends compte que la distribution normale entre dans - + Infinity. Je suppose que les queues peuvent être coupées, donc lorsqu'un aléatoire est calculé à l'extérieur de la plage, recompute. Cela élève la probabilité d'entiers dans la gamme, mais tant que cet effet est tolérable (<5%), c'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); 
    }
}

J'ai probablement besoin de mettre à l'échelle l'écart-type de certains à quel point la gamme, mais je ne comprends pas comment.

Réponse:

    // 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;
    }
Était-ce utile?

La solution

Si la méthode Box-Muller renvoie une distribution normale "standard", elle aura la moyenne 0 et l'écart type 1. Pour transformer une distribution normale standard, vous multipliez votre nombre aléatoire par x pour obtenir un écart-type X, et vous ajoutez y pour obtenir signifie y, si la mémoire me sert correctement.

Voir le Section de l'article de Wikipedia sur la normalisation des variables normales standard (propriété 1) pour une preuve plus formelle.


En réponse à votre commentaire, la règle de base est que 99,7% d'une distribution normale se fera à +/- 3 fois l'écart type. Si vous avez besoin d'une distribution normale de 0 à 100 par exemple, votre moyenne sera à mi-chemin, et votre SD sera (100/2) / 3 = 16,667. Donc, quelles que soient les valeurs que vous retirez de votre algorithme Box-Muller, multipliez par 16.667 pour "étirer" la distribution, puis ajoutez 50 au "centre".


John, en réponse à votre nouveau commentaire, je ne sais vraiment pas à quoi ça sert Next fonction. Il utilise toujours un écart-type de 1 et une moyenne de mi-chemin entre votre min et max.

Si vous voulez une moyenne de Y, avec ~ 99,7% des nombres dans la plage -x à + x, alors vous appelez simplement BoxMuller(Y, X/3).

Autres conseils

Eh bien, le -2 * Sigma .. + 2 * Sigma vous donnera 95% de la courbe de cloche. (Vérifiez la section "Écart-type et intervalles de confiance" dans l'article Wiki déjà mentionné).

Modifiez donc cette pièce:

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

et changer 1.0 (écart-type) à 2.0 (ou même plus si vous voulez une couverture plus de 95%)

return (int)BoxMuller(min + (max - min) / 2.0, 2.0);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top