Quanto è casuale Math.random di JavaScript?


116

Per 6 anni ho avuto una pagina di generatore di numeri casuali sul mio sito web. Per molto tempo, è stato il primo o il secondo risultato su Google per "generatore di numeri casuali" ed è stato utilizzato per decidere decine, se non centinaia di concorsi e disegni su forum di discussione e blog (lo so perché vedo i referrer nel mio log web e di solito vai a dare un'occhiata).

Oggi, qualcuno mi ha inviato un'e-mail per dirmi che potrebbe non essere così casuale come pensavo. Ha provato a generare numeri casuali molto grandi (ad esempio, tra 1 e 10000000000000000000) e ha scoperto che erano quasi sempre lo stesso numero di cifre. In effetti, ho avvolto la funzione in un ciclo in modo da poter generare migliaia di numeri e abbastanza sicuro, per numeri molto grandi, la variazione era solo di circa 2 ordini di grandezza.

Perché?

Ecco la versione in loop, quindi puoi provarla tu stesso:

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

Comprende sia un'implementazione semplice presa dal Mozilla Developer Network sia un codice del 1997 che ho cancellato da una pagina web che non esiste più ("Central Randomizer 1.3" di Paul Houle). Visualizza l'origine per vedere come funziona ciascun metodo.

Ho letto qui e altrove di Mersenne Twister. Quello che mi interessa è perché non ci sarebbe una maggiore variazione nei risultati della funzione Math.random incorporata in JavaScript . Grazie!


"sarnath'd" come in, battuto sul tempo, o in questo caso, la risposta
maetl

5
Se stai cercando la risposta alla domanda nel titolo, vedi stackoverflow.com/questions/2344312/…
Andrew B.

Risposte:


182

Dati numeri compresi tra 1 e 100.

  • 9 hanno 1 cifra (1-9)
  • 90 hanno 2 cifre (10-99)
  • 1 ha 3 cifre (100)

Dati numeri compresi tra 1 e 1000.

  • 9 hanno 1 cifra
  • 90 hanno 2 cifre
  • 900 hanno 3 cifre
  • 1 ha 4 cifre

e così via.

Quindi, se ne selezioni alcuni a caso, la stragrande maggioranza dei numeri selezionati avrà lo stesso numero di cifre, perché la stragrande maggioranza dei valori possibili ha lo stesso numero di cifre.


11
La tua idea di casualità che significa perfettamente e uniformemente distribuita è intrigante ...

19
@ R.Pate - la generazione di numeri casuali non è molto utile a meno che non sia distribuita uniformemente su larga scala
annakata

3
Leggi ancora. @David sta solo affermando che tipo di numeri ci sono tra i limiti, non il risultato della selezione di N numeri casuali. Ammetto che il titolo sia fuorviante.
nikc.org

3
Per la cronaca, ho votato a favore sia questa che le risposte di @jwoolard. Ho scelto questa come risposta accettata perché gli esempi rendono chiaro come un cristallo il motivo per cui la distribuzione dei numeri è distorta ai numeri con più cifre.
Andrew Hedges,

1
@ andrew-hedges ha ragione - questa è la risposta più chiara, ma grazie :)
jwoolard

56

I tuoi risultati sono effettivamente attesi. Se i numeri casuali sono distribuiti uniformemente in un intervallo da 1 a 10 ^ n, allora ti aspetteresti che circa 9/10 dei numeri abbiano n cifre e un ulteriore 9/100 abbia n-1 cifre.


8
Esattamente. La distribuzione del numero di cifre dovrebbe essere distorta. La distribuzione del registro del numero di cifre dovrebbe tuttavia essere uniforme.
Noldorin

45

Esistono diversi tipi di casualità. Math.random ti offre una distribuzione uniforme dei numeri.

Se desideri diversi ordini di grandezza, ti suggerirei di utilizzare una funzione esponenziale per creare quella che viene chiamata distribuzione della legge di potenza :

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

Questa funzione dovrebbe fornire all'incirca lo stesso numero di numeri a 1 cifra dei numeri a 2 cifre e dei numeri a 3 cifre.

Esistono anche altre distribuzioni per numeri casuali come la distribuzione normale (chiamata anche distribuzione gaussiana).


Con questo algoritmo, ho messo la minimum = 1e la maximum = 10e a volte ottenere 11 come risultato. Probabilmente volevi usare al Math.floorposto diMath.round
Sam Eaton il

1
Perché funziona? Trasforma la distribuzione uniforme in distribuzione esponenziale?
shinzou

@shinzou ho chiesto su math.stackexchange e ho ottenuto una formula leggermente diversa come risposta. Ho modificato il codice per riflettere la formula derivata matematicamente da math.stackexchange.
Christian

20

Mi sembra perfettamente casuale! (Suggerimento: dipende dal browser.)

Personalmente, penso che la mia implementazione sarebbe migliore, anche se l'ho rubata a XKCD , che dovrebbe SEMPRE essere riconosciuto:

function random() {
  return 4; // Chosen by a fair dice throw. Guaranteed to be random.
}

19
+1 per aver menzionato che dipende dal browser, -1 per prendere in prestito xkcd senza collegamento.

Obbligatorio o no, poiché è xkcd, viene attribuito. :)
Arafangion

2
OT: Sono sorpreso e felice che "XKCD" sia stata la risposta a una domanda di University Challenge questa settimana: D
Matt Sach

2
Bergi: Un collegamento diretto non è sufficiente?
Arafangion

Penso che significhino che la battuta non è stata citata correttamente ("random = 4;" invece di "return 4;")
Eren Tantekin

18

Il documento seguente spiega come math.random () nei principali browser Web è (non) sicuro: "Tracciamento temporaneo degli utenti nei principali browser e perdita di informazioni e attacchi tra domini" di Amid Klein (2008) . Non è più potente delle tipiche funzioni PRNG integrate in Java o Windows.

D'altra parte, l'implementazione di SFMT del periodo 2 ^ 19937-1 richiede 2496 byte dello stato interno mantenuto per ciascuna sequenza PRNG. Alcune persone potrebbero considerarlo un costo imperdonabile.


1
+1: Il documento menzionato è fantastico, molto al di là di ciò di cui parlava la domanda originale.
Roland Illig

6

Se utilizzi un numero come 10000000000000000000, stai andando oltre la precisione del tipo di dati utilizzato da Javascript. Notare che tutti i numeri generati terminano con "00".


1
Non è un suo problema in questo caso, però.
Joey

3
@Johannes - è uno dei suoi problemi :)
annakata

La distribuzione di IEE754 non è uniforme. Forse puoi rappresentare da 0 a 999 in incrementi di due e avere una precisione sufficiente per questo in modo da notare una distribuzione uniforme su quell'intervallo se scegli il numero molte volte. Il 10% sarà a due cifre e il 90% a tre cifre. Quando inizi a raggiungere numeri davvero alti, però, l'incremento sarà superiore a 1. Potresti solo essere in grado di passare da un trilione di miliardi a un trilione di mille e non un trilione di miliardi e uno. Sebbene per piccoli numeri / scale, questo effetto sarà trascurabile o inesistente. Tuttavia, l'effetto scala avrà un impatto molto maggiore.
jgmjgm

5

Ho provato il generatore di numeri pseudocasuali JS su Chaos Game .

Il mio triangolo di Sierpiński dice che è piuttosto casuale: fractal


2
Ti dispiacerebbe condividere il codice del triangolo qui e jsfiddle / jsbin in modo che possiamo facilmente verificarlo in pratica per diversi browser?
Fabrício Matté

1
OK, ma dammi qualche giorno, perché ho bisogno di tradurre il codice in inglese. Adesso è polacco-inglese e ho molto lavoro.
zie1ony

1
@ zie1ony un paio di giorni sono scaduti.
Trusktr

1
usp :( work, work, work Link: kubaplas.vot.pl/green/fractal Il primo parametro è il nr del vertice. Il secondo è un punto di intersezione (da 0 a 1) di un segmento di linea. Sperimenta solo.
zie1ony

4
Link morto - forse un repo Github invece?
Mark K Cowan,

3

Bene, se stai generando numeri fino a, diciamo, 1e6, si spera che otterrai tutti i numeri con probabilità approssimativamente uguale. Ciò significa anche che hai solo una possibilità su dieci di ottenere un numero con una cifra in meno. Una possibilità su cento di ottenere due cifre in meno, ecc. Dubito che vedrai molta differenza quando usi un altro RNG, perché hai una distribuzione uniforme tra i numeri, non il loro logaritmo.


0

I numeri non casuali distribuiti uniformemente da 1 a N hanno la stessa proprietà. Nota che (in un certo senso) è una questione di precisione. Una distribuzione uniforme su 0-99 (come numeri interi) ha il 90% dei suoi numeri con due cifre. Una distribuzione uniforme su 0-999999 ha 905 dei suoi numeri con cinque cifre.

Qualsiasi insieme di numeri (in alcune condizioni non troppo restrittive) ha una densità. Quando qualcuno vuole discutere di numeri "casuali", la densità di questi numeri dovrebbe essere specificata (come notato sopra). Una densità comune è la densità uniforme. Ce ne sono altri: la densità esponenziale, la densità normale, ecc. Bisogna scegliere quale densità è rilevante prima di proporre un generatore di numeri casuali. Inoltre, i numeri provenienti da una densità possono spesso essere facilmente trasformati in un'altra densità con mezzi cariati.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.