web-dev-qa-db-fra.com

Comment ensemencer une classe aléatoire pour éviter d'obtenir des valeurs aléatoires en double

J'ai le code suivant dans une méthode statique dans une classe statique:

Random r = new Random();
int randomNumber = r.Next(1,100);

J'ai cela dans une boucle et je continue à avoir le même randomNumber!

Des suggestions ici?

108
leora

Vous ne devriez pas créer une nouvelle instance Random dans une boucle. Essayez quelque chose comme:

var rnd = new Random();
for(int i = 0; i < 100; ++i) 
   Console.WriteLine(rnd.Next(1, 100));

La séquence de nombres aléatoires générés par une seule instance Random est supposée être uniformément distribuée. En créant une nouvelle instance Random pour chaque nombre aléatoire de successions rapides, vous risquez de les ensemencer de valeurs identiques et de les faire générer des nombres aléatoires identiques. Bien entendu, dans ce cas, la séquence générée sera loin d'une distribution uniforme.

Par souci d'exhaustivité, si vous avez vraiment besoin de réensemencer un Random, vous créerez une nouvelle instance de Random avec le nouveau germe:

rnd = new Random(newSeed);
99
Mehrdad Afshari

Une bonne génération de semences pour moi est:

Random Rand = new Random(Guid.NewGuid().GetHashCode());

C'est très aléatoire. La graine est toujours différente car elle est également générée de manière aléatoire.

297
joppiesaus

Si, pour une raison quelconque, vous ne pouvez pas utiliser le même Random encore et encore, essayez de l'initialiser avec quelque chose qui change tout le temps, comme le temps lui-même.

new Random(new System.DateTime().Millisecond).Next();

Rappelez-vous que c'est une mauvaise pratique cependant.

EDIT: Le constructeur par défaut tire déjà son origine de l’horloge, et probablement mieux que nous le ferions. Citant de MSDN:

Random (): initialise une nouvelle instance de la classe Random à l'aide d'une valeur de départ par défaut dépendante du temps.

Le code ci-dessous est probablement votre meilleure option:

new Random().Next();
16
PPC

Un peu tard, mais la implémentation utilisée par System.Random est Environment.TickCount:

public Random() 
  : this(Environment.TickCount) {
}

Cela évite de devoir lancer DateTime.UtcNow.Ticks sur un long terme, ce qui est risqué car il ne représente pas de ticks depuis le démarrage du système, mais "le nombre d’intervalles de 100 nanosecondes qui se sont écoulés depuis minuit le 1er janvier 0001 (0:00: 00 UTC le 1 er janvier 0001, dans le calendrier grégorien) ".

Je cherchais une bonne graine entière pour le TestApi's StringFactory.GenerateRandomString

16
Orphid
public static Random Rand = new Random(); // this happens once, and will be great at preventing duplicates

Notez que cela ne doit pas être utilisé à des fins cryptographiques.

3
McKay

cela fonctionne pour moi:

private int GetaRandom()
    {
        Thread.Sleep(1);
        return new Random(DateTime.Now.Millisecond).Next();
    }
3
Omidoo

Une bonne initialisation peut être faite comme ça

Random rnd = new Random((int)DateTime.Now.Ticks);

Les ticks seront uniques et la distribution dans un int avec probablement une perte de valeur sera OK.

0
ZedZed