33 votes

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

Comment puis-je générer des valeurs Int64 et UInt64 aléatoires en utilisant la classe Random en C#?

76voto

Noldorin Points 67794

Cela devrait faire l'affaire. (C'est une méthode d'extension de sorte que vous pouvez l'appeler tout 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);
}

Remplacez simplement Int64 par UInt64 partout si vous voulez des entiers non signés à la place et tout devrait fonctionner correctement.

Remarque : Étant donné qu'aucun contexte n'a été fourni en ce qui concerne la sécurité ou l'aléatoire désiré des nombres générés (en fait, l'OP a spécifiquement mentionné la classe Random), mon exemple traite simplement de la classe Random, qui est la solution préférée lorsque l'aléatoire (souvent quantifié en tant qu'entropie d'information) n'est pas un problème. Par ailleurs, consultez les autres réponses qui mentionnent RNGCryptoServiceProvider (le RNG fourni dans le namespace System.Security), qui peut être utilisé de manière presque identique.

1 votes

+1 pour avoir donné à l'OP ce qu'ils ont demandé tout en mentionnant les limitations de l'utilisation de Random et en offrant une alternative si les limitations de Random sont trop restrictives pour l'utilisation prévue.

5 votes

Notez que cette approche renvoie également des nombres négatifs et Int64.MaxValue, tandis que System.Random.Next() est limité à des nombres positifs incluant 0 mais sans Int32.MaxValue.

0 votes

@Christoph: Oui, bien observé. Cependant, vous pourriez facilement modifier ma méthode pour ne produire que des valeurs positives en ignorant le MSB (bit le plus significatif) du tampon.

29voto

Jon Skeet Points 692016

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

// Suppose que rng fait référence à une instance de System.Random
byte[] bytes = new byte[8];
rng.NextBytes(bytes);
long int64 = BitConverter.ToInt64(bytes, 0);
ulong uint64 = BitConverter.ToUInt64(bytes, 0);

Notez qu'utiliser Random.Next() deux fois, décaler une valeur puis effectuer un OU logique ou une addition ne fonctionne pas. Random.Next() ne produit que des entiers non négatifs, c'est-à-dire qu'il génère 31 bits, pas 32, donc le résultat de deux appels ne produit 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 le faire avec trois appels à Random.Next() cependant.)

0 votes

Oh, bon repérage (commentaire) - je supprime le mien, car le BitConverter etc est déjà bien couvert...

0 votes

D'accord - J'ai inclus cela dans ma réponse plutôt que dans un commentaire pour qu'il soit plus visible. Je vais le laisser maintenant de toute façon en tant qu'avertissement pour l'avenir (sinon, c'est une alternative évidente).

0 votes

En raison du fait que la majorité des générateurs de nombre pseudo-aléatoire (PRNG) LCM sont moins aléatoires dans les bits de faible ordre, générer 2 nombres et les joindre ensemble peut introduire des biais subtils...

10voto

Muad'Dib Points 14260

Voici, cela utilise les services crytpo (pas la classe Random), qui est (théoriquement) un meilleur générateur de nombres aléatoires que la classe Random. Vous pourriez facilement en faire une extension de Random ou créer votre propre classe Random où RNGCryptoServiceProvider est un objet de niveau de classe.

utilisant 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);        
}

0 votes

Il est certainement intéressant de noter, bien que selon la question, l'OP ne semble pas trop se préoccuper de l'aléatoire des nombres générés. Il est également important de réaliser que RNGCryptoServiceProvider est beaucoup plus lent que Random (bien que les performances importent ou non ici).

6voto

Guffa Points 308133

Vous pouvez utiliser le décalage de bits 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();

5voto

sipwiz Points 15291

Je l'utilise toujours pour obtenir ma graine aléatoire (vérification des erreurs supprimée pour des raisons de concision) :

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 l'aléatoire et est apparemment utilisé pour les loteries et autres.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X