web-dev-qa-db-fra.com

Comment générer un nombre aléatoire aléatoire?

Comment générer un entier aléatoire en C #?

1740
Rella

Le Random class est utilisé pour créer des nombres aléatoires. (Pseudo-aléatoire c'est bien sûr.).

Exemple:

Random rnd = new Random();
int month  = rnd.Next(1, 13);  // creates a number between 1 and 12
int dice   = rnd.Next(1, 7);   // creates a number between 1 and 6
int card   = rnd.Next(52);     // creates a number between 0 and 51

Si vous souhaitez créer plusieurs nombres aléatoires, vous devez conserver l'instance Random et la réutiliser. Si vous créez de nouvelles instances trop proches dans le temps, elles produiront la même série de nombres aléatoires que le générateur aléatoire est généré à partir de l'horloge système.

2281
Guffa

La question a l'air très simple mais la réponse est un peu compliquée. Si vous voyez presque tout le monde a suggéré d'utiliser la classe Random et certains ont suggéré d'utiliser la classe de cryptage RNG. Mais alors quand choisir quoi.

Pour cela, nous devons d’abord comprendre le terme RANDOMNESS et sa philosophie.

Je vous encourage à regarder cette vidéo qui décrit en profondeur la philosophie de RANDOMNESS en utilisant C # https://www.youtube.com/watch?v=tCYxc-2-3fY

Première chose, comprenons la philosophie de la RANDOMNESS. Lorsque nous disons à une personne de choisir entre ROUGE, VERT et JAUNE, ce qui se passe en interne. Qu'est-ce qui fait qu'une personne choisit ROUGE, JAUNE ou VERT?

c# Random

Une pensée initiale va à l’esprit des personnes qui décident de son choix, il peut s’agir de la couleur préférée, de la couleur chanceuse, etc. En d’autres termes, un déclencheur initial que nous appelons dans RANDOM le mot SEED. Ce SEED est le point de départ, le déclencheur qui l’incite à sélectionner la valeur RANDOM.

Maintenant, si une graine est facile à deviner, alors ce genre de nombres aléatoires est appelé (pseudo) _ _ et, quand une graine est difficile à deviner, appelé SÉCURISÉ nombre aléatoire.

Par exemple, une personne choisit sa couleur en fonction de la météo et de la combinaison sonore, alors il serait difficile de deviner la graine initiale.

c# Random

Permettez-moi maintenant de faire une déclaration importante: -

* La classe "Random" génère uniquement un nombre aléatoire PSEUDO. Pour générer un nombre aléatoire SECURE, nous devons utiliser la classe "RNGCryptoServiceProvider".

c# Random

Une classe aléatoire prend des valeurs de départ de l'horloge de votre CPU, ce qui est très prévisible. Donc, en d'autres termes, la classe RANDOM de C # génère des nombres pseudo aléatoires, le code ci-dessous est identique.

var random = new Random();
int randomnumber = random.Next()

Tandis que la classe RNGCryptoServiceProvider utilise l'entropie du système d'exploitation pour générer des graines. L'entropie du système d'exploitation est une valeur aléatoire générée à l'aide du son, des clics de souris et du clavier, de la température, etc. Le code ci-dessous indique le même principe.

using (RNGCryptoServiceProvider rg = new RNGCryptoServiceProvider()) 
{ 
    byte[] rno = new byte[5];    
    rg.GetBytes(rno);    
    int randomvalue = BitConverter.ToInt32(rno, 0); 
}

Pour comprendre l'entropie du système d'exploitation, voir cette vidéo à partir de 14h30 https://www.youtube.com/watch?v=tCYxc-2-3fY où la logique de l'entropie du système d'exploitation est expliquée. Donc, en utilisant des mots simples, RNG Crypto génère des nombres aléatoires SÉCURISÉS.

219
Shivprasad Koirala

Chaque fois que vous faites un nouveau Random (), il est initialisé. Cela signifie que dans une boucle serrée, vous obtenez la même valeur plusieurs fois. Vous devez conserver une seule instance aléatoire et continuer à utiliser Next sur la même instance.

//Function to get random number
private static readonly Random getrandom = new Random();

public static int GetRandomNumber(int min, int max)
{
    lock(getrandom) // synchronize
    {
        return getrandom.Next(min, max);
    }
}
213
Pankaj Mishra

Attention, new Random() est créé avec l'horodatage actuel.

Si vous voulez générer un seul nombre , vous pouvez utiliser:

new Random().Next( int.MinValue, int.MaxValue )

Pour plus d'informations, reportez-vous à la classe Random , mais notez que:

Cependant, comme l'horloge a une résolution finie, l'utilisation du constructeur sans paramètre pour créer différents objets aléatoires en succession proche crée des générateurs de nombres aléatoires qui produisent des séquences identiques de nombres aléatoires.

Donc, n'utilisez pas ce code pour générer une série de nombres aléatoires.

85
Fyodor Soikin
Random r = new Random();
int n = r.Next();
46
Joren

Je voulais ajouter une version cryptographiquement sécurisée:

Classe RNGCryptoServiceProvider ( MSDN ou dotnetperls )

Il implémente IDisposable.

using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
{
   byte[] randomNumber = new byte[4];//4 for int32
   rng.GetBytes(randomNumber);
   int value = BitConverter.ToInt32(randomNumber, 0);
}
27
joordan831

Vous pouvez utiliser la méthode StaticRandom de Jon Skeet dans la bibliothèque de classes MiscUtil qu'il a créée pour un nombre pseudo-aléatoire.

using MiscUtil;
...

for (int i = 0; i < 100; 
    Console.WriteLine(StaticRandom.Next());
16
mbcrump

il est préférable d'ensemencer l'objet aléatoire avec les millisecondes actuelles, afin de garantir un nombre aléatoire réel, et vous ne trouverez presque jamais de doublons l'utilisant plusieurs fois.

Random Rand = new Random(DateTime.Now.Millisecond);

Mise à jour

Je sais que new Random() utilise les ticks actuels comme germe, mais l'ensemencement avec les millisecondes actuelles est encore suffisant car son démarrage est correct.

Le dernier point restant est que vous n'avez pas besoin d'initialiser new Random() à chaque fois que vous avez besoin d'un nombre aléatoire, initiez un objet aléatoire, puis utilisez-le autant de fois que nécessaire dans une boucle ou autre.

14
Mohamed Selim

J'ai essayé toutes ces solutions en excluant la réponse COBOL ... lol

Aucune de ces solutions ne suffisait. J'avais besoin de randoms dans une boucle rapide pour int et je recevais des tonnes de valeurs en double, même dans de très larges plages. Après s'être contenté de résultats aléatoires bien trop longtemps, j'ai décidé de finalement aborder ce problème une fois pour toutes.

Tout tourne autour de la graine.

Je crée un entier aléatoire en analysant les non-chiffres de Guid, puis je l'utilise pour instancier ma classe Random.

public int GenerateRandom(int min, int max)
{
    var seed = Convert.ToInt32(Regex.Match(Guid.NewGuid().ToString(), @"\d+").Value);
    return new Random(seed).Next(min, max);
}

Mise à jour: L'amorçage n'est pas nécessaire si vous instanciez une fois la classe Random. Il serait donc préférable de créer une classe statique et d'appeler une méthode à partir de cela.

public static class IntUtil
{
   private static Random random;

   private static void Init()
   {
      if (random == null) random = new Random();
   }

   public static int Random(int min, int max)
   {
      Init();
      return random.Next(min, max);
   }
}

Ensuite, vous pouvez utiliser la classe statique comme si ..

for(var i = 0; i < 1000; i++)
{
   int randomNumber = IntUtil.Random(1,100);
   Console.WriteLine(randomNumber); 
}

J'avoue que j'aime mieux cette approche.

13
Proximo

Les nombres générés par la classe Random incorporée (System.Random) génèrent des nombres pseudo aléatoires.

Si vous voulez de vrais nombres aléatoires, le plus proche que nous puissions obtenir est le "générateur pseudo-aléatoire sécurisé", qui peut être généré à l'aide des classes cryptographiques en C # telles que RNGCryptoServiceProvider.

Même dans ce cas, si vous avez toujours besoin de true nombres aléatoires, vous devrez utiliser une source externe, telle que des dispositifs prenant en compte la décroissance radioactive, en tant que graine pour un générateur de nombres aléatoires. Puisque, par définition, tout nombre généré par des moyens purement algorithmiques ne peut être vraiment aléatoire.

9
Anshita Arya

Réponse modifiée de ici .

Si vous avez accès à un processeur compatible Intel Secure Key, vous pouvez générer des nombres et des chaînes aléatoires réels à l'aide de ces bibliothèques: https://github.com/JebteK/RdRand et https://www.rdrand.com/

Il suffit de télécharger la dernière version de ici , d'inclure Jebtek.RdRand et d'ajouter une instruction using pour elle. Ensuite, tout ce que vous devez faire est la suivante:

// Check to see if this is a compatible CPU
bool isAvailable = RdRandom.GeneratorAvailable();

// Generate 10 random characters
string key       = RdRandom.GenerateKey(10);

 // Generate 64 random characters, useful for API keys 
string apiKey    = RdRandom.GenerateAPIKey();

// Generate an array of 10 random bytes
byte[] b         = RdRandom.GenerateBytes(10);

// Generate a random unsigned int
uint i           = RdRandom.GenerateUnsignedInt();

Si vous n'avez pas de CPU compatible pour exécuter le code, utilisez simplement les services RESTful sur rdrand.com. Avec la bibliothèque de wrapper RdRandom incluse dans votre projet, il vous suffira de le faire (vous recevez 1000 appels gratuits lors de votre inscription):

string ret = Randomizer.GenerateKey(<length>, "<key>");
uint ret   = Randomizer.GenerateUInt("<key>");
byte[] ret = Randomizer.GenerateBytes(<length>, "<key>");
8
JebaDaHut

J'utilise le code ci-dessous pour avoir un nombre aléatoire:

var random = new Random((int)DateTime.Now.Ticks);
var randomValue = random.Next(startValue, endValue + 1);
8
shA.t

C'est la classe que j'utilise. Fonctionne comme RandomNumber.GenerateRandom(1, 666)

internal static class RandomNumber
{
    private static Random r = new Random();
    private static object l = new object();
    private static Random globalRandom = new Random();
    [ThreadStatic]
    private static Random localRandom;
    public static int GenerateNewRandom(int min, int max)
    {
        return new Random().Next(min, max);
    }
    public static int GenerateLockedRandom(int min, int max)
    {
        int result;
        lock (RandomNumber.l)
        {
            result = RandomNumber.r.Next(min, max);
        }
        return result;
    }
    public static int GenerateRandom(int min, int max)
    {
        Random random = RandomNumber.localRandom;
        if (random == null)
        {
            int seed;
            lock (RandomNumber.globalRandom)
            {
                seed = RandomNumber.globalRandom.Next();
            }
            random = (RandomNumber.localRandom = new Random(seed));
        }
        return random.Next(min, max);
    }
}
5
AskethZ
Random random = new Random ();
int randomNumber = random.Next (lowerBound,upperBound);
4
ReRoute

Pour les semences aléatoires fortes, j'utilise toujours CryptoRNG et non Time.

using System;
using System.Security.Cryptography;

public class Program
{
    public static void Main()
    {
        var random = new Random(GetSeed());
        Console.WriteLine(random.Next());
    }

    public static int GetSeed() 
    {
        using (var rng = new RNGCryptoServiceProvider())
        {
            var intBytes = new byte[4];
            rng.GetBytes(intBytes);
            return BitConverter.ToInt32(intBytes, 0);
        }
    }
}
3
Davit Tvildiani

Tant que c'est bon:

Random random = new Random();
int randomNumber = random.Next()

Vous voudriez contrôler la limite (min et max mumbers) la plupart du temps. Vous devez donc spécifier où commence et finit le nombre aléatoire.

La méthode Next() accepte deux paramètres, min et max.

Donc, si je veux que mon nombre aléatoire soit compris entre 5 et 15, je ferais

int randomNumber = random.Next(5, 16)
3
ojonugwa ochalifu

Les nombres calculés par un ordinateur via un processus déterministe ne peuvent, par définition, être aléatoires.

Si vous voulez un véritable nombre aléatoire, le caractère aléatoire provient du bruit atmosphérique ou de la décroissance radioactive.

Vous pouvez essayer par exemple RANDOM.ORG (cela réduit les performances)

2
Stefano Lonati

Je voulais montrer ce qui se passe lorsqu'un nouveau générateur aléatoire est utilisé à chaque fois. Supposons que vous avez deux méthodes ou deux classes nécessitant chacune un nombre aléatoire. Et naïvement vous les codez comme:

public class A
{
    public A()
    {
        var rnd=new Random();
        ID=rnd.Next();
    }
    public int ID { get; private set; }
}
public class B
{
    public B()
    {
        var rnd=new Random();
        ID=rnd.Next();
    }
    public int ID { get; private set; }
}

Pensez-vous que vous obtiendrez deux identifiants différents? NOPE

class Program
{
    static void Main(string[] args)
    {
        A a=new A();
        B b=new B();

        int ida=a.ID, idb=b.ID;
        // ida = 1452879101
        // idb = 1452879101
    }
}

La solution consiste à toujours utiliser un seul générateur aléatoire statique. Comme ça:

public static class Utils
{
    public static readonly Random random=new Random();
}

public class A
{
    public A()
    {
        ID=Utils.random.Next();
    }
    public int ID { get; private set; }
}
public class B
{
    public B()
    {
        ID=Utils.random.Next();
    }
    public int ID { get; private set; }
}
2
ja72
Random Rand = new Random();
int name = Rand.Next()

Mettez toutes les valeurs que vous voulez dans les deuxièmes parenthèses, assurez-vous d’avoir défini un nom en écrivant prop et double tab pour générer le code.

2
user3773367

Vous pouvez essayer avec une valeur de départ aléatoire en utilisant ci-dessous:

var rnd = new Random(11111111); //note: seed value is 11111111

string randomDigits = rnd.Next();

var requestNumber = $"SD-{randomDigits}";
0
Rejwanul Reja

Désolé, OP nécessite en effet une valeur aléatoire int, mais dans le but simple de partager des connaissances si vous souhaitez une valeur aléatoire BigInteger, vous pouvez utiliser l'instruction suivante:

BigInteger randomVal = BigInteger.Abs(BigInteger.Parse(Guid.NewGuid().ToString().Replace("-",""), NumberStyles.AllowHexSpecifier));
0
Ciro Corvino

Le moyen le plus simple est probablement simplement Random.range(1, 3) Cela générerait un nombre compris entre 1 et 2.

0
Gustav Petersen

Je suppose que vous voulez un générateur de nombres aléatoires uniformément distribué, comme ci-dessous. Les nombres aléatoires dans la plupart des langages de programmation, notamment C # et C++, ne sont pas correctement mélangés avant de les utiliser. Cela signifie que vous obtiendrez le même nombre à plusieurs reprises, ce qui n'est pas vraiment aléatoire. Pour éviter de tirer le même nombre à plusieurs reprises, vous avez besoin d'une graine. En règle générale, les ticks dans le temps sont acceptables pour cette tâche. N'oubliez pas que vous obtiendrez le même nombre à plusieurs reprises si vous utilisez la même graine à chaque fois. Donc, essayez d'utiliser toujours des semences différentes. Le temps est une bonne source de semences car ils se disputent toujours.

int GetRandomNumber(int min, int max)
{
    Random Rand = new Random((int)DateTime.Now.Ticks);
    return Rand.Next(min, max);
}

si vous recherchez un générateur de nombres aléatoires pour une distribution normale, vous pouvez utiliser une transformation Box-Muller. Vérifiez la réponse de yoyoyoyosef dans Question aléatoire variable gaussienne. Puisque vous voulez un entier, vous devez convertir la valeur double en entier à la fin.

Random Rand = new Random(); //reuse this if you are generating many
double u1 = 1.0-Rand.NextDouble(); //uniform(0,1] random doubles
double u2 = 1.0-Rand.NextDouble();
double randStdNormal = Math.Sqrt(-2.0 * Math.Log(u1)) *
         Math.Sin(2.0 * Math.PI * u2); //random normal(0,1)
double randNormal =
         mean + stdDev * randStdNormal; //random normal(mean,stdDev^2)

Variables Gaussiennes Aléatoires

0
auto9817