À quel point Math.random de JavaScript est-il aléatoire?

116

Depuis 6 ans, j'ai une page de générateur de nombres aléatoires sur mon site Web. Pendant longtemps, c'était le premier ou le deuxième résultat sur Google pour "générateur de nombres aléatoires" et a été utilisé pour décider des dizaines, voire des centaines de concours et de dessins sur les forums de discussion et les blogs (je le sais car je vois les référents dans mon journaux Web et allez généralement jeter un oeil).

Aujourd'hui, quelqu'un m'a envoyé un courriel pour me dire que ce n'était peut-être pas aussi aléatoire que je le pensais. Elle a essayé de générer de très grands nombres aléatoires (par exemple, entre 1 et 10000000000000000000) et a constaté qu'il s'agissait presque toujours du même nombre de chiffres. En effet, j'ai enveloppé la fonction dans une boucle afin de pouvoir générer des milliers de nombres et bien sûr, pour de très grands nombres, la variation n'était que d'environ 2 ordres de grandeur.

Pourquoi?

Voici la version en boucle, vous pouvez donc l'essayer par vous-même:

http://andrew.hedges.name/experiments/random/randomness.html

Il comprend à la fois une implémentation simple tirée du Mozilla Developer Network et du code de 1997 que j'ai glissé d'une page Web qui n'existe plus ("Central Randomizer 1.3" de Paul Houle). Consultez la source pour voir comment chaque méthode fonctionne.

J'ai lu ici et ailleurs sur Mersenne Twister. Ce qui m'intéresse, c'est pourquoi il n'y aurait pas de plus grandes variations dans les résultats de la fonction Math.random intégrée de JavaScript . Merci!

Andrew Hedges
la source
"sarnath'd" comme dans, battu au coup de poing, ou dans ce cas, la réponse
maetl
5
Si vous cherchez la réponse à la question dans le titre, voir stackoverflow.com/questions/2344312/…
Andrew B.

Réponses:

182

Donné des nombres entre 1 et 100.

  • 9 ont 1 chiffre (1-9)
  • 90 ont 2 chiffres (10-99)
  • 1 comporte 3 chiffres (100)

Donné des nombres entre 1 et 1000.

  • 9 ont 1 chiffre
  • 90 ont 2 chiffres
  • 900 ont 3 chiffres
  • 1 comporte 4 chiffres

etc.

Donc, si vous en sélectionnez au hasard, alors cette grande majorité des nombres sélectionnés aura le même nombre de chiffres, car la grande majorité des valeurs possibles ont le même nombre de chiffres.

Quentin
la source
11
Votre idée de l'aléatoire signifiant parfaitement et uniformément distribué est intrigante ...
19
@ R.Pate - la génération de nombres aléatoires n'est pas très utile à moins qu'elle ne soit uniformément répartie sur une longue échelle
annakata
3
Lire à nouveau. @David indique uniquement le type de nombres entre les limites et non le résultat de la sélection de N nombres aléatoires. J'admets que le titre est trompeur.
nikc.org
3
Pour mémoire, j'ai voté pour les réponses de ceci et de @ jwoolard. J'ai choisi celle-ci comme réponse acceptée parce que les exemples montrent clairement pourquoi la distribution des nombres est biaisée vers des nombres avec plus de chiffres.
Andrew Hedges
1
@ andrew-hedges tout à fait raison - c'est la réponse la plus claire, mais merci :)
jwoolard
56

Vos résultats sont réellement attendus. Si les nombres aléatoires sont uniformément distribués dans une plage de 1 à 10 ^ n, alors vous vous attendez à ce qu'environ 9/10 des nombres aient n chiffres et 9/100 supplémentaires aient n-1 chiffres.

jwoolard
la source
8
Exactement. On s'attend à ce que la distribution du nombre de chiffres soit biaisée. La distribution du journal du nombre de chiffres doit cependant être uniforme.
Noldorin
45

Il existe différents types d'aléa. Math.random vous donne une distribution uniforme des nombres.

Si vous voulez des ordres de grandeur différents, je suggère d'utiliser une fonction exponentielle pour créer ce qu'on appelle une distribution de loi de puissance :

function random_powerlaw(mini, maxi) {
    return Math.ceil(Math.exp(Math.random()*(Math.log(maxi)-Math.log(mini)))*mini)
}

Cette fonction devrait vous donner à peu près le même nombre de nombres à 1 chiffre que les nombres à 2 chiffres et que les nombres à 3 chiffres.

Il existe également d'autres distributions pour les nombres aléatoires comme la distribution normale (également appelée distribution gaussienne).

Christian
la source
Avec cet algorithme, je mets le minimum = 1et le maximum = 10et j'en obtenais parfois 11. Vous vouliez probablement utiliser à la Math.floorplace deMath.round
Sam Eaton
1
Pourquoi ça marche? Transforme-t-il une distribution uniforme en distribution exponentielle?
shinzou
@shinzou J'ai demandé sur math.stackexchange et j'ai obtenu une formule légèrement différente comme réponse. J'ai changé le code pour refléter la formule dérivée mathématiquement de math.stackexchange.
Christian
20

Cela me semble parfaitement aléatoire! (Indice: cela dépend du navigateur.)

Personnellement, je pense que ma mise en œuvre serait meilleure, même si je l'ai volée à XKCD , qui devrait TOUJOURS être reconnu:

function random() {
  return 4; // Chosen by a fair dice throw. Guaranteed to be random.
}
Arafangion
la source
19
+1 pour mentionner qu'il dépend du navigateur, -1 pour emprunter xkcd sans lien.
Obligatoire ou non, puisque c'est xkcd, il est attribué. :)
Arafangion
2
OT: Je suis surpris et heureux que "XKCD" ait été la réponse à une question du Défi universitaire cette semaine: D
Matt Sach
2
Bergi: Un lien direct ne suffit pas?
Arafangion
Je pense qu'ils veulent dire que la blague n'a pas été citée correctement ("random = 4;" au lieu de "return 4;")
Eren Tantekin
18

L'article suivant explique comment math.random () dans les principaux navigateurs Web est (non) sécurisé: «Suivi temporaire des utilisateurs dans les principaux navigateurs et fuites d'informations et attaques interdomaines» par Amid Klein (2008) . Ce n'est pas plus fort que les fonctions PRNG intégrées typiques de Java ou Windows.

D'autre part, la mise en œuvre de SFMT de la période 2 ^ 19937-1 nécessite 2496 octets de l'état interne maintenu pour chaque séquence PRNG. Certaines personnes peuvent considérer cela comme un coût impardonnable.

jj1bdx
la source
1
+1: Le papier mentionné est génial, bien au-delà de la question originale.
Roland Illig
6

Si vous utilisez un nombre comme 10000000000000000000, vous allez au-delà de la précision du type de données utilisé par Javascript. Notez que tous les nombres générés se terminent par "00".

Greg
la source
1
Ce n'est pas son problème dans ce cas, cependant.
Joey
3
@Johannes - c'est l' un de ses problèmes :)
annakata
La distribution de IEE754 n'est même pas. Peut-être que vous pouvez représenter de 0 à 999 par incréments de deux et avoir suffisamment de précision pour cela afin que vous remarquiez une distribution uniforme sur cette plage si vous choisissez un nombre plusieurs fois. 10% sera à deux chiffres et 90% à trois chiffres. Cependant, lorsque vous commencez à atteindre des chiffres vraiment élevés, l'augmentation dépassera 1. Vous ne pourrez peut-être passer que d'un billion de milliards à un billion de milliards de mille et non d'un billion de milliards et un. Bien que pour de petits nombres / échelles, cet effet sera négligeable à inexistant. L'effet d'échelle aura cependant beaucoup plus d'impact.
jgmjgm
5

J'ai essayé le générateur de nombres pseudo-aléatoires JS sur Chaos Game .

Mon triangle Sierpiński dit que c'est assez aléatoire: Fractale

zie1ony
la source
2
Pourriez-vous partager le code du triangle ici et jsfiddle / jsbin afin que nous puissions facilement le vérifier dans la pratique pour différents navigateurs?
Fabrício Matté
1
OK, mais donnez-moi quelques jours, car j'ai besoin de traduire le code en anglais. Maintenant c'est polonais-anglais et j'ai beaucoup de travail.
zie1ony
1
@ zie1ony quelques jours sont écoulés.
trusktr
1
usp :( travail, travail, travail Lien: kubaplas.vot.pl/green/fractal Le premier paramètre est le nr du sommet. Le second est un point d'intersection (de 0 à 1) du segment de ligne. Il suffit d'expérimenter.
zie1ony
4
Lien mort - peut-être un repo Github à la place?
Mark K Cowan du
3

Eh bien, si vous générez des nombres jusqu'à, disons, 1e6, vous obtiendrez tous les nombres avec une probabilité approximativement égale. Cela signifie également que vous n'avez qu'une chance sur dix d'obtenir un numéro avec un chiffre en moins. Une chance sur cent d'obtenir deux chiffres de moins, etc. Je doute que vous constatiez une grande différence lors de l'utilisation d'un autre RNG, car vous avez une distribution uniforme entre les nombres, pas leur logarithme.

Joey
la source
0

Les nombres non aléatoires uniformément répartis de 1 à N ont la même propriété. Notez que (dans un certain sens) c'est une question de précision. Une distribution uniforme sur 0-99 (sous forme d'entiers) a 90% de ses nombres ayant deux chiffres. Une distribution uniforme sur 0-999999 a 905 de ses numéros à cinq chiffres.

Tout ensemble de nombres (dans certaines conditions pas trop restrictives) a une densité. Quand quelqu'un veut discuter de nombres «aléatoires», la densité de ces nombres doit être spécifiée (comme indiqué ci-dessus). Une densité commune est la densité uniforme. Il y en a d'autres: la densité exponentielle, la densité normale, etc. Il faut choisir quelle densité est pertinente avant de proposer un générateur de nombres aléatoires. En outre, les nombres provenant d'une densité peuvent souvent être facilement transformés en une autre densité par des moyens carieux.

ttw
la source