Question

Je veux générer des nombres aléatoires avec un intervalle (n à m, par exemple 100 à 150), mais au lieu de je veux purement aléatoire que les résultats soient basés sur la distribution normale.

Par Je veux dire que, en général, je veux que les chiffres « regroupés » autour de 125.

J'ai trouvé ce paquet de nombres aléatoires qui semble avoir beaucoup de ce que j'ai besoin: http : //codeproject.com/KB/recipes/Random.aspx

Il prend en charge une variété de générateurs aléatoires (y compris mersiene twister) et peut appliquer le générateur à une distribution.

Mais je suis confus, si j'utilise un générateur de distribution normale, les nombres aléatoires sont d'environ -6 à 8 (apparemment la vraie plage est float.min à float.max).

Comment faire une échelle de ma gamme nécessaire?

Était-ce utile?

La solution

Une distribution normale standard a une moyenne de 0 et un écart type de 1; si vous souhaitez effectuer une distribution avec m moyenne et s écart, il suffit de multiplier par s puis ajouter m. Étant donné que la distribution normale est théoriquement infinie, vous ne pouvez pas avoir un plafond dur sur votre plage par exemple (100 à 150) sans rejeter explicitement les numéros qui tombent en dehors de celui-ci, mais avec un choix approprié de l'écart, vous pouvez être assuré que (par exemple) 99% de vos numéros sera dans la plage.

A propos de 99,7% d'une population est de +/- 3 écarts-types, donc si vous choisissez le vôtre pour être au sujet (25/3), il devrait bien fonctionner.

Vous voulez quelque chose comme: (normal * 8.333) + 125

Autres conseils

Par souci d'intérêt, il est assez simple de générer des nombres aléatoires normalement distribués à partir d'un RNG uniforme (bien que cela doit se faire par paires):

Random rng = new Random();
double r = Math.Sqrt(-2 * Math.Log(rng.NextDouble()));
double θ = 2 * Math.Pi * rng.NextDouble();
double x = r * Math.Cos(θ);
double y = r * Math.Sin(θ);

x et y contiennent maintenant deux nombres aléatoires indépendants, normale de moyenne 0 et de variance 1. Vous pouvez l'échelle et de les traduire au besoin pour obtenir la plage que vous voulez (comme interjay explique).


Explication:

Cette méthode est appelée Box-Muller transformer. Il utilise la propriété de l'unité à deux dimensions gaussien que la valeur de densité elle-même, p = exp(-r^2/2), est uniformément répartie entre 0 et 1 (constante de normalisation enlevée par souci de simplicité).

Comme vous pouvez générer une telle valeur facilement à l'aide d'un RNG uniforme, vous vous retrouvez avec un contour circulaire de r = sqrt(-2 * log(p)) de rayon. Vous pouvez ensuite générer une seconde variable aléatoire uniforme entre 0 et 2*pi pour vous donner un θ angle qui définit un point unique sur votre contour circulaire. Enfin, vous pouvez générer deux IID normale des nombres aléatoires en transformant à partir des coordonnées polaires (r, θ) 'en coordonnées cartésiennes (x, y).

Cette propriété - que p est uniformément répartie -. Ne tient pas pour d'autres dimensionalités, ce qui est la raison pour laquelle vous devez générer exactement deux variables normales que à un moment

La réponse de tzaman est correct, mais lorsque vous utilisez la bibliothèque que vous liée il y a une façon plus simple que d'effectuer le calcul vous-même: L'objet NormalDistribution a des propriétés inscriptibles Mu (ce qui signifie la moyenne) et Sigma (écart-type). Donc, en passant par les numéros de tzaman, ensemble Mu à 125 et Sigma à 8,333.

Cela peut être trop simpliste pour vos besoins, mais un moyen rapide et pas cher pour obtenir un nombre aléatoire avec une distribution qui est pondérée vers le centre est d'ajouter simplement 2 (ou plus) des nombres aléatoires.

Pensez quand vous lancez deux dés à 6 faces et les ajouter. La somme est le plus souvent 7, puis 6 et 8, puis 5 et 9, etc., et que rarement 2 ou 12.

Voici un autre Algoritm qui n'a pas besoin de calculer Sin / Cos, ni besoin de savoir Pi. Ne me demandez pas au sujet de l'arrière-plan théorique. Je l'ai trouvé quelque part une fois et c'est ce que je l'ai utilisé depuis. Je soupçonne que c'est une sorte de normalisation de la même boîte-Muller transformation qui @Will Vousden mentionne. Elle produit également des résultats par paires.

L'exemple est VBscript; assez facile à convertir dans une autre langue.

Sub calcRandomGauss (byref y1, byref y2)
    Dim x1, x2, w
    Do
        x1 = 2.0 * Rnd() - 1.0
        x2 = 2.0 * Rnd() - 1.0
        w = x1 * x1 + x2 * x2
    Loop While w >= 1.0 Or w = 0  'edited this line, thanks Richard

    w = Sqr((-2.0 * Log(w)) / w )
    y1 = x1 * w
    y2 = x2 * w
End Sub

Une approche différente à ce problème utilise le beta (qui a une plage difficile, contrairement à la distribution normale) et consiste à choisir les paramètres appropriés tels que la distribution a donné écart moyen et le niveau (racine carrée de la variance). Voir cette question.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top