684 votes

En quoi les nombres pseudo-aléatoires et les nombres véritablement aléatoires sont-ils différents et pourquoi est-ce important ?

Je n'ai jamais vraiment compris ça. Disons que vous écrivez un petit programme dans n'importe quel langage qui lance des dés (en utilisant les dés comme exemple). Après 600 000 lancers, chaque numéro aura été lancé environ 100 000 fois, ce qui correspond à ce que j'attends.

Pourquoi existe-t-il des sites web consacrés au "vrai hasard" ? Compte tenu de l'observation ci-dessus, il est certain que les chances d'obtenir un numéro sont presque exactement égales à 1 sur le nombre de numéros parmi lesquels il peut choisir.

Je l'ai essayé dans Python : Voici le résultat de 60 millions de lancers. La plus grande variation est de 0,15. Ce n'est pas aussi aléatoire que ça peut l'être ?

1 - 9997653 2347.0
2 - 9997789 2211.0
3 - 9996853 3147.0
4 - 10006533 -6533.0
5 - 10002774 -2774.0
6 - 9998398 1602.0

1398voto

rgajrawala Points 101

Jouons au poker informatique, juste toi, moi et un serveur en qui nous avons confiance. Le serveur utilise un générateur de nombres pseudo-aléatoires qui est initialisé avec une graine de 32 bits juste avant de jouer. Il y a donc environ 4 milliards de jeux de cartes possibles.

J'ai cinq cartes en main - apparemment, nous ne jouons pas au Texas Hold 'Em. Supposons que les cartes soient distribuées une à moi, une à toi, une à moi, une à toi, et ainsi de suite. J'ai donc les première, troisième, cinquième, septième et neuvième cartes du jeu.

Plus tôt, j'ai lancé le générateur de nombres pseudo-aléatoires quatre milliards de fois, une fois avec chaque graine, et j'ai noté la première carte générée pour chacune dans une base de données. Supposons que ma première carte soit la reine de pique. Cette carte n'apparaît qu'une fois en tant que première carte dans un jeu sur 52 de ces jeux possibles. Nous avons donc réduit le nombre de jeux possibles de quatre milliards à environ 80 millions.

Supposons que ma deuxième carte soit le trois de cœur. Je lance maintenant mon RNG 80 millions de fois de plus en utilisant les 80 millions de graines qui produisent la reine de pique comme premier numéro. Cela me prend quelques secondes. Je note tous les jeux de cartes qui produisent le trois de cœur comme troisième carte - la deuxième carte de ma main. Cela ne représente à nouveau qu'environ 2 % des jeux de cartes, ce qui nous ramène à 2 millions de jeux de cartes.

Supposons que la troisième carte de ma main soit le 7 de trèfle. J'ai une base de données de 2 millions de jeux qui distribuent mes deux cartes ; je lance mon RNG 2 millions de fois de plus pour trouver les 2% de ces jeux qui produisent le 7 de trèfle comme troisième carte, et nous ne sommes plus qu'à 40 000 jeux.

Vous voyez comment ça se passe. Je fais tourner mon RNG 40000 fois de plus pour trouver toutes les graines qui produisent ma quatrième carte, ce qui nous amène à 800 jeux de cartes, puis je le fais tourner 800 fois de plus pour obtenir les ~20 graines qui produisent ma cinquième carte, et maintenant je viens de générer ces vingt jeux de cartes et je sais que vous avez une des vingt mains possibles. De plus, j'ai une très bonne idée de ce que je vais tirer ensuite.

Vous voyez maintenant pourquoi le véritable caractère aléatoire est important ? De la façon dont vous le décrivez, vous pensez que distribution est importante, mais la distribution n'est pas ce qui rend un processus aléatoire. Imprévisibilité est ce qui rend un processus aléatoire.

UPDATE

D'après les commentaires (maintenant supprimés en raison de leur nature non constructive), au moins 0,3 % des personnes qui ont lu cet article ne comprennent pas où je veux en venir. Quand les gens argumentent contre des points que je n'ai pas soulevés, ou pire, argumentent にとって points que je a fait faire sur la en supposant que je ne les ai pas faites, je sais alors que je dois m'expliquer plus clairement et plus soigneusement.

Il semble y avoir une confusion particulière autour du mot distribution Je tiens donc à rappeler les usages avec précaution.

Les questions qui se posent sont les suivantes :

  • En quoi les nombres pseudo-aléatoires et les nombres réellement aléatoires diffèrent-ils ?
  • Pourquoi cette différence est-elle importante ?
  • Les différences ont-elles quelque chose à voir avec la distribution de la sortie du PRNG ?

Commençons par considérer le parfait pour générer un jeu de cartes aléatoire avec lequel jouer au poker. Nous verrons ensuite en quoi les autres techniques de génération de jeux de cartes sont différentes, et s'il est possible de tirer parti de cette différence.

Commençons par supposer que nous avons une boîte magique étiquetée TRNG . En entrée, nous lui donnons un nombre entier n supérieur ou égal à un, et en sortie, il nous donne un nombre vraiment aléatoire compris entre un et n, inclus. La sortie de la boîte est entièrement imprévisible (lorsqu'on lui donne un nombre différent de un) et que tout nombre compris entre un et n est aussi probable qu'un autre ; c'est-à-dire que les distribution es uniforme . (Il existe d'autres contrôles statistiques plus avancés du caractère aléatoire que nous pourrions effectuer ; j'ignore ce point car il n'est pas pertinent pour mon argument. TRNG est parfaitement statistiquement aléatoire par hypothèse).

Nous commençons avec un jeu de cartes non mélangé. Nous demandons à la boîte un nombre entre 1 et 52 -- c'est-à-dire, TRNG(52) . Quel que soit le nombre qu'elle donne en retour, nous comptons ce nombre de cartes de notre jeu trié et nous retirons cette carte. Elle devient la première carte du jeu mélangé. Ensuite, nous demandons TRNG(51) et faites de même pour sélectionner la deuxième carte, et ainsi de suite.

Une autre façon de voir les choses est la suivante : il y a 52 ! = 52 x 51 x 50 ... x 2 x 1 decks possibles, soit environ 2 226 . Nous avons choisi l'un d'entre eux au hasard.

Maintenant, nous distribuons les cartes. Quand je regarde mes cartes, j'ai aucune idée quelles cartes vous avez. (En dehors du fait évident que vous n'avez aucune des cartes que j'ai.) Il peut s'agir de n'importe quelles cartes, avec la même probabilité.

Permettez-moi donc de m'assurer que j'explique clairement la situation. Nous avons distribution uniforme de chaque sortie individuelle de TRNG(n) chacun choisit un nombre entre 1 et n avec une probabilité de 1/n. De plus, le résultat de ce processus est que nous avons choisi l'un des 52 ! jeux possibles avec une probabilité de 1/52 !, donc la distribution sur l'ensemble des jeux possibles es également uniforme.

Très bien.

Supposons maintenant que nous ayons une boîte moins magique, étiquetée PRNG . Avant que vous puissiez l'utiliser, il doit être semé avec un nombre non signé de 32 bits.

ASIDE : Pourquoi 32 ? Ne pourrait-on pas l'ensemencer avec un nombre de 64, 256 ou 10000 bits ? Bien sûr. Mais (1) en pratique, la plupart des PRNGs du commerce sont ensemencés avec un nombre de 32 bits, et (2) si vous disposez de 10000 bits d'aléa pour faire l'ensemencement, pourquoi utiliser un PRNG ? Vous disposez déjà d'une source de 10000 bits d'aléa !

Quoi qu'il en soit, revenons à la façon dont le PRNG fonctionne : une fois qu'il est ensemencé, vous pouvez l'utiliser de la même façon que vous utilisez TRNG . C'est-à-dire que vous lui passez un nombre, n, et il vous renvoie un nombre compris entre 1 et n, inclus. De plus, la distribution de cette production est plus ou moins uniforme. . C'est-à-dire que lorsque nous demandons PRNG pour un nombre compris entre 1 et 6, on obtient 1, 2, 3, 4, 5 ou 6 environ un sixième du temps, quelle que soit la graine.

Je tiens à insister plusieurs fois sur ce point car il semble être celui qui déroute certains commentateurs. La distribution du PRNG est uniforme de deux manières au moins. Premièrement, supposons que nous choisissions une graine particulière. Nous nous attendons à ce que la séquence PRNG(6), PRNG(6), PRNG(6)... un million de fois produirait une distribution uniforme de nombres entre 1 et 6. Et deuxièmement, si nous choisissions un million de graines différentes et appelions PRNG(6) 一旦 pour chaque graine, là encore on s'attendrait à une distribution uniforme de nombres de 1 à 6. L'uniformité du PRNG dans l'une ou l'autre de ces opérations n'est pas pertinente pour l'attaque que je décris. .

Ce processus est dit pseudo-aléatoire parce que le comportement de la boîte est en fait entièrement déterministe ; elle choisit entre 2 possibilités. 32 les comportements possibles en fonction de la graine. C'est-à-dire, une fois qu'il est ensemencé, PRNG(6), PRNG(6), PRNG(6), ... produit un séquence de nombres avec une distribution uniforme, mais cette séquence est entièrement déterminée par la semence. Pour une séquence donnée d'appels, disons PRNG(52), PRNG(51) ... et ainsi de suite, il n'y a que 2 32 séquences possibles. La graine choisit essentiellement celle que nous obtenons.

Pour générer un jeu, le serveur génère maintenant une graine. (Comment ? Nous reviendrons sur ce point.) Puis il appelle PRNG(52) , PRNG(51) et ainsi de suite pour générer le jeu, comme précédemment.

Ce système est sensible à l'attaque que j'ai décrite. Pour attaquer le serveur, nous commençons, à l'avance, par ensemencer notre propre copie de la boîte avec 0 et demandons PRNG(52) et écrivez-le. Puis on réensemence avec 1, on demande PRNG(52) et écrivez-le, jusqu'à 2. 32 -1.

Maintenant, le serveur de poker qui utilise le PRNG pour générer des jeux de cartes doit générer une graine d'une manière ou d'une autre. La manière dont ils le font n'a pas d'importance. Ils pourraient appeler TRNG(2^32) pour obtenir une graine vraiment aléatoire. Ou bien ils pourraient prendre l'heure actuelle comme graine, ce qui n'est pas du tout aléatoire ; je sais quelle heure il est autant que vous. Le point de mon attaque est que cela n'a pas d'importance, parce que j'ai ma base de données . Lorsque je vois ma première carte, je peux éliminer 98% des graines possibles. Lorsque je vois ma deuxième carte, je peux éliminer 98% de plus, et ainsi de suite, jusqu'à ce que je puisse finalement descendre à une poignée de graines possibles, et savoir avec une grande probabilité ce que vous avez en main.

Maintenant, encore une fois, je veux souligner que l'hypothèse ici est que si nous avons appelé PRNG(6) un million de fois, nous obtiendrions chaque nombre environ un sixième du temps. . Cette distribution est (plus ou moins) uniforme y si l'uniformité de cette distribution est tout ce qui vous intéresse. c'est très bien. Le but de la question était y a-t-il d'autres choses que la distribution de PRNG(6) dont nous nous soucions ? et la réponse est oui . Nous nous préoccupons de imprévisibilité également.

Une autre façon de voir le problème est que même si la distribution d'un million d'appels à PRNG(6) pourrait être bien, parce que le PRNG choisit parmi seulement 2 32 comportements possibles, il ne peut pas générer tous les jeux possibles. Il ne peut générer que 2 32 de la 2 226 decks possibles ; une fraction minuscule. Donc la distribution sur l'ensemble de tous les ponts est très mauvais. Mais encore une fois, l'attaque fondamentale ici est basée sur notre capacité à réussir prédire le comportement passé et futur de PRNG à partir d'un petit échantillon de sa production.

Je vais le dire une troisième ou quatrième fois pour être sûr que ça rentre dans le crâne. Il y a trois distributions ici. D'abord, la distribution du processus qui produit la graine aléatoire de 32 bits. Cela peut être parfaitement aléatoire, imprévisible et uniforme et l'attaque fonctionnera toujours . Deuxièmement, la distribution d'un million d'appels à PRNG(6) . Cela peut être parfaitement uniforme et l'attaque fonctionnera quand même. Troisièmement, la distribution des jeux choisis par le processus pseudo-aléatoire que j'ai décrit. Cette distribution est extrêmement pauvre ; seule une infime partie des jeux IRL possibles peut être choisie. L'attaque dépend de la prévisibilité du comportement du PRNG sur la base d'une connaissance partielle de sa sortie .

ASIDE : Cette attaque nécessite que l'attaquant connaisse ou soit capable de deviner l'algorithme exact utilisé par le PRNG. La question de savoir si cela est réaliste ou non reste ouverte. Cependant, lors de la conception d'un système de sécurité, vous devez le concevoir de manière à ce qu'il soit protégé contre les attaques, même si l'attaquant connaît tous les algorithmes du programme. . En d'autres termes, la partie d'un système de sécurité qui doit rester secrète pour que le système soit sûr est appelée la "clé". Si la sécurité de votre système dépend du fait que les algorithmes que vous utilisez restent secrets, alors votre clé contient ces algorithmes . C'est un extrêmement une position faible dans laquelle se trouver !

On avance.

Supposons maintenant que nous ayons une troisième boîte magique appelée CPRNG . Il s'agit d'une version cryptée de PRNG . Il prend une graine de 256 bits plutôt qu'une graine de 32 bits. Il partage avec PRNG la propriété que la graine choisit parmi l'une des 2 256 comportements possibles. Et comme nos autres machines, elle possède la propriété qu'un grand nombre d'appels à CPRNG(n) produisent une distribution uniforme de résultats entre 1 et n : chacun se produit 1/n du temps. Pouvons-nous exécuter notre attaque contre elle ?

Notre attaque originale nous oblige à stocker 2 32 les correspondances entre les graines et les PRNG(52) . Mais 2 256 est un nombre beaucoup plus grand ; il est totalement infaisable d'exécuter CPRNG(52) ce nombre de fois et stocker les résultats.

Mais supposons qu'il y ait autre manière de prendre la valeur de CPRNG(52) et en déduire un fait sur la graine ? Nous avons été assez stupides jusqu'à présent, en forçant brutalement toutes les combinaisons possibles. Peut-on regarder à l'intérieur de la boîte magique, comprendre comment elle fonctionne et déduire des faits sur la graine en se basant sur le résultat ?

Non. Les détails sont trop compliqués à expliquer, mais les CPRNG sont intelligemment conçus pour qu'il soit infaisable de déduire cualquier fait utile sur la graine à partir de la première sortie de CPRNG(52) ou de cualquier sous-ensemble de la sortie, quelle que soit la taille .

OK, supposons maintenant que le serveur utilise CPRNG pour générer des platines. Il a besoin d'une graine de 256 bits. Comment choisit-il cette graine ? Si elle choisit une valeur qu'un attaquant peut prédire puis soudainement l'attaque redevient viable . Si nous pouvons déterminer que parmi les 2 256 graines possibles, seuls quatre milliards d'entre eux sont susceptibles d'être choisis par le serveur, alors nous sommes de retour en affaires . Nous pouvons à nouveau monter cette attaque, en ne faisant attention qu'au petit nombre de graines qui peuvent être générées.

Le serveur doit donc faire en sorte que le nombre de 256 bits soit uniformément distribué -- c'est-à-dire que chaque graine possible est choisie avec une probabilité de 1/2 256 . En fait, le serveur devrait appeler TRNG(2^256)-1 pour générer la semence pour CPRNG .

Et si je pouvais pirater le serveur et y pénétrer pour voir quelle graine a été choisie ? Dans ce cas, l'attaquant connaît le passé et le futur complets du CPRNG. . L'auteur du serveur doit se prémunir contre cette attaque ! (Bien sûr, si je réussis à monter cette attaque, je pourrai probablement aussi transférer l'argent directement sur mon compte bancaire, ce qui n'est peut-être pas si intéressant. Le fait est que la graine doit être un secret difficile à deviner, et un nombre vraiment aléatoire de 256 bits est assez difficile à deviner).

Pour en revenir à mon point précédent sur la défense en profondeur, la graine de 256 bits est le meilleur moyen d'assurer la sécurité. clé à ce système de sécurité. L'idée d'un CPRNG est que le système est sécurisé tant que la clé est sécurisée Même si tous les autres faits concernant l'algorithme sont connus, tant que vous pouvez garder la clé secrète, les cartes de l'adversaire sont imprévisibles.

OK, donc la graine doit être à la fois secrète et uniformément distribuée car si elle ne l'est pas, nous pouvons monter une attaque. Nous avons par hypothèse que la distribution des sorties de CPRNG(n) est uniforme. Qu'en est-il de la distribution sur l'ensemble de tous les jeux de cartes possibles ?

Vous pourriez dire : il y a 2 256 séquences possibles produites par le CPRNG, mais il n'y en a que 2. 226 decks possibles. Il y a donc plus de séquences possibles que de jeux de cartes, donc tout va bien ; chaque jeu de cartes possible-IRL est maintenant (avec une forte probabilité) possible dans ce système. Et c'est un bon argument, sauf que...

2 226 est seulement un approximation de 52 ! Divisez-le. 2 256 /52 ! ne peut pas être un nombre entier car, d'une part, 52 ! est divisible par 3 mais aucune puissance de deux ne l'est ! Puisqu'il ne s'agit pas d'un nombre entier, nous nous trouvons maintenant dans la situation où tous les jeux de cartes sont possible mais certains jeux sont plus probables que d'autres .

Si cela n'est pas clair, considérez la situation avec des chiffres plus petits. Supposons que nous ayons trois cartes, A, B et C. Supposons que nous utilisions un PRNG avec une graine de 8 bits, il y a donc 256 graines possibles. Il existe 256 sorties possibles de PRNG(3) en fonction de la graine ; il est impossible qu'un tiers d'entre elles soient A, un tiers B et un tiers C, car 256 n'est pas divisible de façon égale par 3. Il doit y avoir un petit biais en faveur de l'une d'entre elles.

De même, 52 ne se divise pas en 2. 256 Il doit donc y avoir un parti pris pour certaines cartes en tant que première carte choisie et un parti pris pour d'autres.

Dans notre système original avec une graine de 32 bits, il y avait un biais massif et la grande majorité des jeux possibles n'étaient jamais produits. Dans ce système, tous les jeux peuvent être produits, mais la distribution des platines est toujours défectueuse . Certaines terrasses sont très légèrement plus probable que d'autres.

Maintenant la question est : avons-nous une attaque basée sur cette faille ? et la réponse est en pratique, probablement pas . Les CPRNG sont conçus de manière à ce que si la graine est vraiment aléatoire puis il est impossible, d'un point de vue informatique, de faire la différence entre CPRNG y TRNG .

OK, alors résumons.

En quoi les nombres pseudo-aléatoires et les nombres réellement aléatoires diffèrent-ils ?

Ils diffèrent par le niveau de prévisibilité qu'ils présentent.

  • Les nombres véritablement aléatoires ne sont pas prévisibles.
  • Tous les nombres pseudo-aléatoires sont prévisibles si la graine peut être déterminée ou devinée.

Pourquoi cette différence est-elle importante ?

Parce qu'il y a des applications où la sécurité du système repose sur imprévisibilité .

  • Si un TRNG est utilisé pour choisir chaque carte, le système est inattaquable.
  • Si un CPRNG est utilisé pour choisir chaque carte, le système est sûr si la graine est à la fois imprévisible et inconnue.
  • Si l'on utilise un PRNG ordinaire avec un petit espace de semence, le système n'est pas sûr, que la semence soit imprévisible ou inconnue ; un espace de semence suffisamment petit est sensible aux attaques par force brute du type que j'ai décrit.

La différence a-t-elle quelque chose à voir avec la distribution de la sortie du PRNG ?

L'uniformité de la distribution ou son absence pour appels individuels a RNG(n) n'est pas pertinent pour les attaques que j'ai décrites.

Comme nous l'avons vu, les deux PRNG y CPRNG produisent de mauvaises distributions de la probabilité de choisir un jeu de cartes individuel parmi tous les jeux de cartes possibles. Le site PRNG est bien pire, mais les deux ont des problèmes.

Une dernière question :

Si TRNG est tellement meilleur que CPRNG, qui est à son tour tellement meilleur que PRNG, pourquoi quelqu'un utilise-t-il CPRNG ou PRNG ?

Pour deux raisons.

Premièrement : les dépenses. TRNG est coûteux . Il est difficile de générer des nombres véritablement aléatoires. Les CPRNGs donnent de bons résultats pour un nombre arbitraire d'appels avec seulement un appel à TRNG pour la semence. L'inconvénient est bien sûr que vous devez garder cette graine secrète .

Deuxièmement : parfois nous 欲する la prévisibilité et tout ce qui nous importe est une bonne distribution. Si vous générez des données "aléatoires" en tant qu'entrées de programme pour une suite de tests, et qu'elles révèlent un bogue, il serait bon que l'exécution de la suite de tests produise à nouveau le bogue !

J'espère que c'est maintenant beaucoup plus clair.

Enfin, si vous avez aimé cet article, vous apprécierez peut-être d'autres lectures sur le thème du hasard et des permutations :

168voto

Bruce Barnett Points 281

Comme le dit Eric Lippert, il ne s'agit pas seulement de distribution. Il existe d'autres façons de mesurer le caractère aléatoire.

L'un des premiers générateurs de nombres aléatoires possède une séquence dans le bit le moins significatif - il alterne les 0 et les 1. Par conséquent, le LSB était prévisible à 100%. Mais vous devez vous soucier de plus que cela. Chaque bit doit être imprévisible.

Voici une bonne façon d'envisager le problème. Disons que vous générez 64 bits d'aléatoire. Pour chaque résultat, prenez les 32 premiers bits (A), et les 32 derniers bits (B), et faites-en un index dans un tableau x[A,B]. Maintenant, effectuez le test un million de fois, et pour chaque résultat, incrémentez le tableau de ce nombre, c'est-à-dire X[A,B]++ ;

Dessinez maintenant un diagramme en 2D, où plus le chiffre est grand, plus le pixel à cet endroit est lumineux.

Si c'est vraiment aléatoire, la couleur devrait être un gris uniforme. Mais vous pouvez obtenir des modèles. Prenez par exemple ce diagramme du "caractère aléatoire" du numéro de séquence TCP du système Windows NT :

Windows NT

ou même celle de Windows 98 :

Windows 98

Et voici le caractère aléatoire de l'implémentation du routeur Cisco (IOS). Cisco ISO

Ces diagrammes sont une courtoisie de Document de Micha Zalewski . Dans ce cas particulier, si l'on peut prédire quel sera le numéro de séquence TCP d'un système, on peut se faire passer pour ce système lorsqu'on établit une connexion avec un autre système - ce qui permettrait de détourner des connexions, d'intercepter des communications, etc. Et même si on ne peut pas prédire le prochain numéro 100% du temps, si on peut provoquer la création d'une nouvelle connexion sous notre contrôle nous pouvons augmenter les chances de réussite. Et lorsque les ordinateurs peuvent générer 100 000 connexions en quelques secondes, les chances de réussite d'une attaque passent d'astronomiques à possibles, voire probables.

94voto

Dj S Points 101

Bien que les nombres pseudo-aléatoires générés par les ordinateurs soient acceptables pour la majorité des cas d'utilisation rencontrés par les utilisateurs d'ordinateurs, il existe des scénarios qui requièrent complètement des nombres aléatoires imprévisibles.

Dans les applications sensibles en matière de sécurité, comme le cryptage, un générateur de nombres pseudo-aléatoires (PRNG) peut produire des valeurs qui, bien qu'aléatoires en apparence, sont en fait prévisibles par un attaquant. Une personne qui tente de craquer un système de cryptage peut être en mesure de deviner les clés de cryptage si un PRNG a été utilisé et si l'attaquant dispose d'informations sur l'état du PRNG. Par conséquent, pour de telles applications, il est nécessaire d'utiliser un générateur de nombres aléatoires qui produit des valeurs qui sont vraiment impossibles à deviner. Notez que Certains PRNG sont conçus pour être cryptographiquement sûrs. et sont utilisables pour ces applications sensibles à la sécurité.

Vous trouverez plus d'informations sur les attaques RNG dans le document suivant cet article de Wikipedia .

80voto

Tony D Points 61

Je l'ai essayé en Python : Voici le résultat de 60 millions de lancers. La variation la plus élevée est d'environ 0,15. Ce n'est pas aussi aléatoire que ça ?

En fait, c'est si "bon" que c'en est mauvais ... Toutes les réponses existantes se concentrent sur prévisibilité étant donné une petite séquence de valeurs initiales. Je voudrais soulever une autre question :

     votre distribution a une déviation standard beaucoup plus petite que celle des rouleaux aléatoires.

Le vrai hasard ne vient pas tout à fait que proche de la moyenne de "presque exactement 1 sur le nombre de numéros qu'il peut choisir" que vous utilisez comme indication de la qualité.

Si vous regardez cette question de Stack Exchange sur les distributions de probabilité pour les jets de dés multiples vous verrez une formule pour l'écart type de N lancers de dés (en supposant des résultats réellement aléatoires) :

 sqrt(N * 35.0 / 12.0).

En utilisant cette formule, le écart type pour :

  • 1 million de rouleaux, c'est 1708
  • 60 millions de rouleaux, c'est 13229

Si on regarde vos résultats :

  • 1 million de rouleaux : stddev(1000066, 999666, 1001523, 999452, 999294, 999999) vaut 804
  • 60 millions de rouleaux : stddev(9997653, 9997789, 9996853, 10006533, 10002774, 9998398) est de 3827

On ne peut pas s'attendre à ce que l'écart-type d'un échantillon fini corresponde exactement à la formule, mais il devrait s'en rapprocher. Pourtant, à 1 million de rouleaux, vous avez moins de la moitié de l'écart-type approprié, et à 60 millions, moins d'un tiers - la situation empire, et ce n'est pas une coïncidence.....

Les pseudo-RNG ont tendance à se déplacer dans une séquence de nombres distincts, en commençant par le germe et en ne revenant pas au nombre original pendant une période spécifique. Par exemple, les implémentations de l'ancienne bibliothèque C rand() ont généralement une période de 2^32, et ils visitent chaque nombre entre 0 et 2^32-1 exactement une fois avant de répéter la graine. Ainsi, si vous simulez 2^32 lancers de dés, le pré-module ( % ) comprendrait chaque nombre de 0 à 2^32, le nombre de résultats de 1 à 6 serait de 715827883 ou 715827882 (2^32 n'est pas un multiple de 6), et l'écart-type ne serait donc que trivialement supérieur à 0. En utilisant la formule ci-dessus, l'écart-type correct pour 2^32 rouleaux est de 111924. Quoi qu'il en soit, au fur et à mesure que le nombre de lancers pseudo-aléatoires augmente, l'écart-type converge vers 0. On peut s'attendre à ce que le problème soit important lorsque le nombre de rouleaux est une fraction significative de la période, mais certains pseudo-RNG peuvent présenter des problèmes plus graves - ou des problèmes même avec moins d'échantillons - que d'autres.

Ainsi, même si vous ne vous souciez pas des vulnérabilités cryptographiques, dans certaines applications, il peut être important d'avoir des distributions qui n'ont pas de résultats trop uniformes, artificiellement. Certains types de simulation essaient tout particulièrement de déterminer les conséquences de la inégale qui se produisent naturellement avec de grands échantillons de résultats aléatoires individuels, mais ils sont sous-représentés dans certains résultats de pRNG. Si vous essayez de simuler la réaction d'une grande population à un événement donné, ce problème pourrait radicalement altérer vos résultats, conduisant à des conclusions totalement inexactes.


Pour donner un exemple concret : Supposons qu'un mathématicien dise au programmeur d'une machine de poker qu'après 60 millions de lancers simulés - utilisés pour faire clignoter des centaines de petites "lumières" autour de l'écran, s'il y a eu 10 013 229 ou plus de six, ce qui, selon le mathématicien, représente un écart de 1 stddev par rapport à la moyenne, il devrait y avoir un petit paiement. Selon le Règle du 68-95-99.7 (Wikipedia) cela devrait arriver vers 16% du temps (~68% se situent à l'intérieur d'un écart-type / seulement la moitié en dehors sont au-dessus). Avec votre générateur de nombres aléatoires, cela correspond à environ 3,5 écarts types au-dessus de la moyenne : Sous 0.025% chance - presque aucun client ne bénéficie de cet avantage. Voir le tableau des écarts supérieurs sur la page que nous venons de mentionner, en particulier :

| Range    | In range   | Outside range | Approx. freq. for daily event  |
| µ ± 1   | 0.68268... | 1 in 3        | Twice a week                   |
| µ ± 3.5 | 0.99953... | 1 in 2149     | Every six years                |

53voto

Will P. Points 129

Je viens d'écrire ce générateur de nombres aléatoires pour générer des jets de dés.

def get_generator():
  next = 1
  def generator():
    next += 1
    if next > 6:
      next = 1
    return next
  return generator

Vous l'utilisez comme ceci

>> generator = get_generator()
>> generator()
1
>> generator()
2
>> generator()
3
>> generator()
4
>> generator()
5
>> generator()
6
>> generator()
1

etc etc. Seriez-vous heureux d'utiliser ce générateur pour un programme qui exécute un jeu de dés ? N'oubliez pas que sa distribution est exactement ce que vous attendez d'un générateur "vraiment aléatoire" !

Les générateurs de nombres pseudo-aléatoires font essentiellement la même chose : ils génèrent des nombres prévisibles avec la bonne distribution. Ils sont mauvais pour la même raison que le générateur de nombres aléatoires simpliste ci-dessus - ils ne conviennent pas aux situations où vous avez besoin d'une véritable imprévisibilité, et pas seulement d'une distribution correcte.

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X