web-dev-qa-db-fra.com

Pourquoi Random.Next () renvoie toujours le même nombre

Considérez cette méthode:

private static int GenerateRandomNumber(int seed, int max)
{
   return new Random(seed).Next(max);
}

Sur ma machine, l’exécution de cette boucle produit le même nombre de 1500 itérations:

  for (int i = 0; i < 1501; i++)
            {
                int random = GenerateRandomNumber(100000000, 999999999);
                Console.WriteLine(random.ToString());
                Console.ReadKey();
            }

Je reçois 145156561, pour chaque itération.

Je n’ai pas de problème urgent, j’étais simplement curieux à propos de ce comportement car .Next (max) dit "Retourne un nombre négatif random inférieur au maximum spécifié. Je ne comprends peut-être pas quelque chose de fondamental.

18
kd7

Vous créez toujours une nouvelle instance avec la même graine, puis saisissez le premier maximum. En utilisant une graine, vous garantissez les mêmes résultats.

Si vous souhaitez une génération de nombres statiques et aléatoires produisant des résultats différents, vous devez la retravailler un peu. Cependant, comme Random n’est pas threadsafe, il nécessite une certaine synchronisation lorsqu’il est utilisé de manière statique. Quelque chose comme:

private static Random random;
private static object syncObj = new object();
private static void InitRandomNumber(int seed)
{
     random = new Random(seed);
}
private static int GenerateRandomNumber(int max)
{
     lock(syncObj)
     {
         if (random == null)
             random = new Random(); // Or exception...
         return random.Next(max);
     }
}
39
Reed Copsey

Le problème est que vous créez une nouvelle instance aléatoire avec le même numéro d'origine à chaque fois. Vous devez créer une seule instance aléatoire (la stocker dans un fichier statique si nécessaire) et appeler simplement la méthode suivante sur cette même instance. 

La génération de nombres aléatoires n’est pas vraiment aléatoire, voir cette entrée Wikipedia pour plus de détails.

6
Eric Giguere

Dilbert a rencontré le même problème en 2001:

http://dilbert.com/strips/comic/2001-10-25/

Coïncidence?

Je ne pense pas.

Et random.org accepte: http://www.random.org/analysis/

6
dbrin

Le générateur de nombres pseudo-aléatoires fonctionne généralement en choisissant une graine, puis en générant une séquence déterministe basée sur cette graine. En choisissant chaque fois la même graine, vous générez la même séquence.

Il existe "seulement" 2 ^ 32 séquences aléatoires différentes dans .NET.

3
Jens

Vous ne savez pas comment fonctionnent les composants internes. Consultez le wiki pour cela, mais c'est très simple.

public class MathCalculations
{
    private Random rnd = new Random();

    public Int32 getRandom(Int32 iMin, Int32 iMax)
    {
        return rnd.Next(iMin, iMax);
    }
}

public class Main
{
    MathCalculations mathCalculations = new MathCalculations();
    for (int i = 0; i < 6; i++)
    {
        getRandom(0,1000);
    }
}

va générer Number1, Number2, Number3, Number4, Number5, Number6 (1 graine, 1 séquence de plusieurs nombres, random * pas vraiment, mais environ *)

si vous faites cependant ceci:

public class MathCalculations
{
    public Int32 getRandom(Int32 iMin, Int32 iMax)
    {  
        Random rnd = new Random();
        return rnd.Next(iMin, iMax);
    }
}

public class Main
{
    MathCalculations mathCalculations = new MathCalculations();
    for (int i = 0; i < 6; i++)
    {
        getRandom(0,1000);
    }
}

Vous obtiendrez maintenant Number1, Number1, Number1, Number1, Number1, Number1 (1 graine, 6 séquences égales de plusieurs nombres, toujours choisir le même numéro de départ dans chaque séquence égale). change avec le temps .. mais vous devez attendre un certain temps pour cela, néanmoins, vous ne choisissez jamais le numéro2 de la séquence.

La raison en est que chaque fois que vous générez une nouvelle séquence avec la même graine, la séquence est donc toujours la même, et chaque fois que votre génération aléatoire choisit le premier nombre de sa séquence, bien sûr toujours le même.

Je ne sais pas si cela est techniquement correct selon les méthodes sous-jacentes du générateur aléatoire, mais c'est ainsi que cela se comporte.

2
user957537

Si quelqu'un cherche une "solution" "rapide et sale" (et j'utilise ce terme avec prudence), cela suffira pour la plupart.

int secondsSinceMidnight = Convert.ToInt32(DateTime.Now.Subtract(DateTime.Today).TotalSeconds);
Random Rand = new Random(secondsSinceMidnight); 
var usuallyRandomId = Rand.Next();

S'il vous plaît noter mon utilisation de habituellement aléatoire. Je conviens que l’article marqué comme réponse est une manière plus correcte de le faire. 

0
AnthonyJ

Salam à tous, Cela m'a rendu fou aussi. La réponse est simple Changer la graine avant de générer au hasard.

Exemple: Je souhaite générer un nombre aléatoire compris entre 1 et 10

Random rnd = new Random(DateTime.Now.Seconds);
int random_number = rnd.Next(10);

Placez-le dans une boucle et exécutez-le trois fois. Il donnera des nombres aléatoires inférieurs à 10.

0
Talha