web-dev-qa-db-fra.com

Générer des valeurs aléatoires en C #

Comment générer des valeurs aléatoires Int64 et UInt64 à l'aide de la classe Random en C #?

32
SyncMaster

Cela devrait faire l'affaire. (Il s'agit d'une méthode d'extension vous permettant de l'appeler comme vous appelez les méthodes normales Next ou NextDouble sur un objet Random).

public static Int64 NextInt64(this Random rnd)
{
    var buffer = new byte[sizeof(Int64)];
    rnd.NextBytes(buffer);
    return BitConverter.ToInt64(buffer, 0);
}

Il suffit de remplacer Int64 par UInt64 partout si vous voulez plutôt des entiers non signés et tout devrait bien fonctionner.

Remarque: Puisqu'aucun contexte n'a été fourni concernant la sécurité ou le caractère aléatoire souhaité des nombres générés (en fait, le PO mentionnait spécifiquement la classe Random), mon exemple traite simplement de la classe Random, qui est la solution préférée lorsque le caractère aléatoire (souvent quantifié en tant que entropie d'informations ) n'est pas un problème. Pour plus d’intérêt, voir les autres réponses qui mentionnent RNGCryptoServiceProvider (le groupe de ressources stratégiques (RNG) fourni dans l’espace de nom System.Security), qui peut être utilisé presque à l’identique.

73
Noldorin

Utilisez Random.NextBytes() et BitConverter.ToInt64 / BitConverter.ToUInt64 .

// Assume rng refers to an instance of System.Random
byte[] bytes = new byte[8];
rng.NextBytes(bytes);
long int64 = BitConverter.ToInt64(bytes, 0);
ulong uint64 = BitConverter.ToUInt64(bytes, 0);

Notez que l'utilisation de Random.Next() deux fois, décaler une valeur puis ORing/ajouter ne fonctionne pas. Random.Next() ne produit que des entiers non négatifs, c’est-à-dire qu’il génère 31 bits et non 32, de sorte que le résultat de deux appels ne génère que 62 bits aléatoires au lieu des 64 bits requis pour couvrir la plage complète de Int64/UInt64. ( La réponse de Guffa montre comment faire avec trois appels à Random.Next() cependant.)

29
Jon Skeet

Voilà, cela utilise le crytpo services (pas la classe Random) , qui est (théoriquement) un meilleur RNG que la classe Random. Vous pouvez facilement en faire une extension de Random ou créer votre propre classe Random où RNGCryptoServiceProvider est un objet de niveau classe.

using System.Security.Cryptography;
public static Int64 NextInt64()
{
   var bytes = new byte[sizeof(Int64)];    
   RNGCryptoServiceProvider Gen = new RNGCryptoServiceProvider();
   Gen.GetBytes(bytes);    
   return BitConverter.ToInt64(bytes , 0);        
}
9
Muad'Dib

Vous pouvez utiliser bit shift pour assembler un nombre aléatoire de 64 bits à partir de nombres aléatoires de 31 bits, mais vous devez utiliser trois nombres de 31 bits pour obtenir suffisamment de bits:

long r = rnd.Next();
r <<= 31;
r |= rnd.Next();
r <<= 31;
r |= rnd.Next();
6
Guffa

J'utilise toujours ceci pour obtenir ma graine aléatoire (vérification d'erreur supprimée pour des raisons de brièveté):

m_randomURL = "https://www.random.org/cgi-bin/randnum?num=1&min=1&max=1000000000";
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(m_randomURL);
StreamReader stIn = new StreamReader(req.GetResponse().GetResponseStream());
Random Rand = new Random(Convert.ToInt32(stIn.ReadToEnd()));

random.org utilise le bruit atmosphérique pour générer le caractère aléatoire et est apparemment utilisé pour les loteries et autres.

5
sipwiz

Vous ne dites pas comment vous allez utiliser ces nombres aléatoires ... Gardez à l'esprit que les valeurs renvoyées par Random ne sont pas "sécurisées de manière cryptographique" et qu'elles ne doivent pas être utilisées pour des choses impliquant de (grands) secrets ou (beaucoup) d'argent.

3
Ðаn

Vous pouvez créer un tableau byte , le remplir avec des données aléatoires puis le convertir en long (Int64) et ulong (UInt64).

byte[] buffer = new byte[sizeof(Int64)];
Random random = new Random();

random.NextBytes(buffer);
long signed = BitConverter.ToInt64(buffer, 0);

random.NextBytes(buffer);
long unsigned = BitConverter.ToUInt64(buffer, 0);
1
Samuel

Une autre réponse avec RNGCryptoServiceProvider au lieu de Random. Ici, vous pouvez voir comment supprimer le MSB afin que le résultat soit toujours positif.

public static Int64 NextInt64()
{
    var buffer = new byte[8];
    new RNGCryptoServiceProvider().GetBytes(buffer);
    return BitConverter.ToInt64(buffer, 0) & 0x7FFFFFFFFFFFFFFF;
}
0
sventevit