2010-02-14 9 views
11

Je cherche à générer un nombre aléatoire entre 1 et 5 millions. Le processus ne doit pas être rapide (bien que ce serait bien si c'était le cas), mais il doit être aussi aléatoire que possible (je sais que rien n'est aléatoire). J'ai une variété de sources de données pour la graine.Numéros aléatoires utilisant C#

Je ne suis pas sûr si la classe .NETRandom va être assez bon pour cela.

Ceci sera utilisé pour sélectionner un ticket gagnant.

+5

Définir clairement et précisément "aussi aléatoire que possible". Pour obtenir un signal réellement "aussi aléatoire que possible", vous avez besoin d'une source d'entropie - la graine - qui a plus de bits d'entropie que l'élément aléatoire généré à partir de cette graine. Donc, si vous avez déjà une variété de sources de données pour la graine, et qu'ils sont à forte entropie, alors vous avez déjà terminé. Il suffit d'extraire 24 bits de votre source d'entropie, ce qui vous donne un nombre entre 0 et 16 millions ** aussi aléatoire que possible compte tenu de votre source d'entropie **. –

+2

En outre, il serait extrêmement utile si vous avez décrit ce que vous allez utiliser ce nombre aléatoire pour. –

+3

Re: votre mise à jour: Maintenant, vous n'êtes plus dans le domaine des mathématiques et de la technologie, mais dans le domaine des réglementations légales. La plupart des gens qui lisent ce ne sont pas des avocats familiers avec les lois concernant les caractéristiques qu'un dispositif qui choisit le gagnant d'une loterie doit posséder. Je recommanderais de consulter un avocat et un statisticien avant de consacrer plus de temps à la recherche d'une solution technique. Il est certain qu'aucune solution "pseudo-aléatoire" * simple * ne sera acceptable; on peut facilement déterminer quel est le prochain numéro gagnant parmi les précédents avec un PRNG. –

Répondre

17

La System.Random classe est probablement assez bon:

nombres pseudo-aléatoires sont choisis avec une probabilité égale d'un ensemble fini de nombres. Les nombres choisis ne sont pas complètement aléatoires parce qu'un algorithme mathématique défini est utilisé pour les sélectionner, mais ils sont suffisamment aléatoires pour des raisons pratiques. L'implémentation actuelle de la classe Random est basée sur l'algorithme du générateur de nombres aléatoires soustractifs de Donald E. Knuth. Pour plus d'informations, voir D. E. Knuth. "L'Art de la Programmation Informatique, volume 2: Algorithmes Seminumerical". Addison-Wesley, Reading, MA, deuxième édition, 1981.

La seule chose que vous devez surveiller est que vous ne pas réutiliser la même graine trop souvent:

Si le même La graine est utilisée plusieurs fois, la même série de nombres est générée. Une façon de produire des séquences différentes est de rendre la valeur de départ dépendante du temps, produisant ainsi une série différente avec chaque nouvelle instance de Random.

+1

Voir ici http://connect.microsoft.com/VisualStudio/feedback/details/634761/system -random-serious-bug Il est mal codé et donc peut-être pas assez bon – evolvedmicrobe

+0

@evolvedmicrobe: Après avoir exécuté un tas de tests statistiques sur une version de 'System.Random' avec un correctif corrigeant ce bug particulier, ce n'est pas clair pour moi qu'il n'y a pas d'autres choses sur le RNG qui devraient être plus inquiétantes. Certes, il a plusieurs problèmes différents: https://github.com/dotnet/corefx/issues/23298 – fuglede

7

Si vous avez besoin d'un nombre aléatoire cryptographique, utilisez la classe System.Security.Cryptography.RNGCryptoServiceProvider ou utilisez la méthode d'usine RandomNumberGenerator.Create() pour créer le générateur de nombres aléatoires configuré par défaut.

+3

RNGCryptServiceProvider fonctionne sur le remplissage des tableaux d'octets, vous devez donc revenir à un int et vérifier qu'il se trouve dans la bonne plage – zebrabox

+1

+1 pour le commentaire de @ zebrabox, plus: si la valeur générée est hors de portée, ne modifiez PAS opérateur) car cela peut provoquer un biais pour certaines valeurs. Boucle autour et génère une autre valeur à la place. – devstuff

+0

@devstuff Ce qui est une raison de plus de ne pas utiliser System.Random puisque leur implémentation de Next (...) est biaisée (ils ne semblent pas utiliser '%' mais les nombres ne sont pas également probables). – CodesInChaos

0

Random .NET devrait être bien pour cela:

var random = new Random(System.DateTime.Now.Millisecond); 

int randomNumber = random.Next(1, 5000000); 
+1

Cela ne fonctionne que pour une variable locale, c'est un accident qui attend de se produire. –

+0

Devrait être int randomNumber = random.Next (1, 5000001); lorsque la méthode .Net renvoie un nombre incluant la limite inférieure mais excluant la limite supérieure. –

+0

Cela dépend du contexte où le nombre est utilisé si une milliseconde est une graine assez bonne. Les machines à sous ont été piratées de cette façon. – Paco

5

Voir le blog de Jon Skeet Revisiting Randomness un très bon examen de l'utilisation Randomness:

Revisiter aléatoire
Presque toutes les questions de débordement de pile qui contient les mots « au hasard » et « répéta "a la même réponse de base. Il est l'un des « pièges » les plus courants dans .NET, Java, et sans doute d'autres plates-formes : création d'un nouveau générateur de nombres aléatoires sans spécifier une graine dépendra de l'instant actuelle du temps. L'heure actuelle comme mesurée par l'ordinateur ne changement très souvent par rapport à la façon dont souvent vous pouvez créer et utiliser un générateur de nombres aléatoire - si le code qui à plusieurs reprises crée une nouvelle instance de au hasard et l'utilise prendra fin une fois jusqu'à montrant beaucoup de répétition.

more...

+0

"plus ..." lien est maintenant rompu. –

1

Si vous êtes à la recherche de vrais nombres aléatoires, alors vous devriez envisager d'utiliser un générateur de nombres aléatoires en ligne qui utilise phénomène naturel, comme http://www.random.org, qui utilise le bruit atmosphérique. Les vrais nombres aléatoires font aussi de bonnes graines pour les générateurs de nombres pseudo-aléatoires. Sipwiz montre comment l'utiliser en C# dans sa réponse: Generate random values in C#

Il est également discuté ici: http://www.vcskicks.com/random-number-generator.php.

Il y a beaucoup d'angles avec les générateurs de nombres aléatoires. Une implémentation alternative intéressante est ISSAC (ttp: //burtleburtle.net/bob/rand/isaac.html), qui contient aussi une bonne discussion sur les biais et autres, et il y a aussi une version C# (http://burtleburtle.net/bob/rand/isaacafa.html).

5

Il y avait en fait un très bon article que j'ai lu assez récemment sur les différents types de PRNG et comment ils se comportent en termes de plusieurs tests aléatoires différents. Malheureusement, je n'arrive pas à le trouver maintenant. L'essentiel de cela, cependant, était que les générateurs de nombres aléatoires par défaut dans presque tous les langages de programmation populaires sont assez naïfs et ont des biais assez importants.

Une autre réponse mentionne déjà qu'aucun PRNG, quel que soit le degré de sophistication de l'algorithme, n'est assez bon pour les applications cryptographiques. C'est vrai. Puisque vous mentionnez que cela sera utilisé pour "sélectionner un ticket gagnant", ignorons cela pour le moment.

L'algorithme Knuth utilisé par la classe .NET System.Random est optimisé principalement pour la vitesse, pas pour la distribution aléatoire. Il est «assez aléatoire» pour de nombreuses raisons, dont la plupart des applications ne s'éloignent jamais trop, mais dans le domaine du jeu et de la simulation statistique, la plupart des gens semblent penser que c'est un mauvais choix. C'est mieux que les LCG qui étaient utilisés par défaut dans les bibliothèques plus anciennes, mais vous ne voulez toujours pas l'utiliser pour quelque chose comme un loto. Ne vous méprenez pas en pensant que vous utilisez simplement une source cryptographique, soit. Le problème avec les RNG cryptographiques est qu'ils remplissent un flux d'octets, mais le transformer en un seul entier aléatoire entre x et et exige que vous fassiez de l'arithmétique modulaire (ou arrondi - même résultat dans les deux cas). Et si votre gamme aléatoire ne se divise pas de façon parfaite en n'importe quelle puissance de 2 est définie par la longueur de l'octet, alors vous allez vous retrouver avec un biais dans les nombres inférieurs. Les données générées ont une entropie élevée, mais votre résultat sera biaisé. Par exemple, disons simplement que vous obtenez un nombre aléatoire "parfait" de 1 à 10 et que vous voulez le transformer en un nombre aléatoire compris entre 1 et 7. Comment le faites-vous? Calculer simplement result % 7 sera fortement biaisé vers les nombres 1-3. Il y a quelques façons de réduire le biais lors de l'utilisation d'un RNG crypto mais le point que j'essaie de faire est que les RNG cryptographiques sont conçus pour les applications cryptographiques, et l'utilisation d'un de ceux pour une simulation Monte Carlo n'est généralement pas la meilleure idée. Pour autant que je sache, le "bon" PRNG le plus populaire actuellement, qui est couramment utilisé dans les applications de jeu, est le Mersenne Twister. Il y a un .NET implementation here. Cet algorithme passe tous les Diehard Tests pour la distribution aléatoire; il ne montre presque aucun biais et est un bon choix lorsque vous utilisez des nombres aléatoires pour des applications probabilistes et statistiques. La bibliothèque scientifique GNU a également un numéro de RNG algorithms et, sans surprise, le Twister de Mersenne est en tête de liste.Cependant, certains des autres valent la peine d'être regardés par curiosité; RANLUX marque également assez haut sur l'essai irréductible IIRC.

Eric a raison avec son commentaire, bien sûr; toute cette information est pour rien si vous n'avez pas d'exigences techniques spécifiques sur "comment aléatoire" vous avez besoin de vos nombres aléatoires pour être. J'utilise une définition qui serait applicable à une application de jeu/de jeu à faible impact (c'est-à-dire pas un site majeur de jeu enregistré avec des millions de visiteurs par jour - il y a des règles plus strictes sur le hasard).

+0

La bibliothèque C# n'est pas basée sur la méthode de Knuth, ils l'ont gâchée – evolvedmicrobe

+0

@evolvedmicrobe: [C'est ce que dit leur documentation] (http://msdn.microsoft.com/fr-fr/library/system.random (v = vs .110) .aspx). Avez-vous une citation ou une preuve pour prouver le contraire? – Aaronaught

+0

oui, ils l'ont essayé ici et je me suis vérifié en décompilant: http://connect.microsoft.com/VisualStudio/feedback/details/634761/system-random-serious-bug – evolvedmicrobe

3

Pour générer un nombre aléatoire, créez un objet de classe Random, puis utilisez la fonction Next de cet objet pour générer un nombre aléatoire. Il a beaucoup de surcharges comme:

Next(int minimum, int maximum); 
Next(int Maximum); 

où vous pouvez spécifier la gamme minimum et maximum entre lequel vous voulez le nombre aléatoire.

extrait de code:

Random random = new Random(); 
int maxValue = 100; 

int r = random.Next(maxValue); 
3

La classe System.Random est très problématique et n'est pas un bon ajustement à l'exigence. En théorie, il devrait fournir de meilleurs résultats que de nombreux autres générateurs pseudo-aléatoires. C'est un port d'exemple C direct et littéral pour un Générateur de Fibonacci Lagressé (LFG) fourni à la page 283 de la deuxième édition de 'Recettes Numériques en C' (le code a été réécrit dans les éditions ultérieures). Les LFG utilisent un meilleur algorithme que les Linear Congruential Generators (LCG) utilisés dans de nombreuses autres bibliothèques (par exemple, Java).

Malheureusement, l'implémentation de Microsoft de la classe System.Random comporte un bogue. Voir http://connect.microsoft.com/VisualStudio/feedback/details/634761/system-random-serious-bug pour plus d'informations. Il semble que quelqu'un a accidentellement tapé '21' quand il fallait taper '31'. Cela compromet les caractéristiques pseudo-aléatoires de l'algorithme. Le lien inclut une explication de la part de MS quant à la raison pour laquelle ils se sentent incapables de corriger l'erreur à ce stade.

+0

Merci pour la réponse détaillée. Nous avons fini par utiliser un matériel rng mais merci pour l'info et le lien! – LiamB

Questions connexes