Jak losowy jest kod JavaScript Math.random?


116

Od 6 lat mam na swojej stronie generator liczb losowych . Przez długi czas był to pierwszy lub drugi wynik w Google dla „generatora liczb losowych” i był używany do decydowania o dziesiątkach, jeśli nie setkach konkursów i rysunków na forach dyskusyjnych i blogach (wiem, bo widzę odnośniki w moim dzienniki internetowe i zwykle zajrzyj).

Dzisiaj ktoś wysłał mi e-maila z informacją, że może nie być tak przypadkowe, jak myślałem. Próbowała wygenerować bardzo duże liczby losowe (np. Od 1 do 10000000000000000000) i odkryła, że ​​są one prawie zawsze taką samą liczbą cyfr. Rzeczywiście, zawinąłem funkcję w pętlę, dzięki czemu mogłem wygenerować tysiące liczb i oczywiście, dla bardzo dużych liczb, zmienność wynosiła tylko około 2 rzędów wielkości.

Czemu?

Oto wersja zapętlona, ​​więc możesz ją wypróbować:

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

Zawiera zarówno prostą implementację zaczerpniętą z sieci Mozilla Developer Network, jak i kod z 1997 roku, który usunąłem ze strony internetowej, która już nie istnieje („Central Randomizer 1.3” Paula Houle'a). Wyświetl źródło, aby zobaczyć, jak działa każda metoda.

Czytałem tutaj i gdzie indziej o Mersenne Twister. Interesuje mnie to, dlaczego nie byłoby większych odchyleń w wynikach z wbudowanej funkcji Math.random JavaScript . Dzięki!


„sarnath'd” jak w, pobity na pięści, czyli w tym przypadku odpowiedź
maetl

5
Jeśli szukasz odpowiedzi na pytanie w tytule, zobacz stackoverflow.com/questions/2344312/…
Andrew B.

Odpowiedzi:


182

Podano liczby od 1 do 100.

  • 9 ma 1 cyfrę (1-9)
  • 90 ma 2 cyfry (10–99)
  • 1 ma 3 cyfry (100)

Podano liczby od 1 do 1000.

  • 9 ma 1 cyfrę
  • 90 ma 2 cyfry
  • 900 ma 3 cyfry
  • 1 ma 4 cyfry

i tak dalej.

Jeśli więc wybierzesz jakieś losowo, to ogromna większość wybranych liczb będzie miała taką samą liczbę cyfr, ponieważ zdecydowana większość możliwych wartości ma tę samą liczbę cyfr.


11
Twój pomysł na przypadkowość, co oznacza idealne i równomierne rozłożenie, jest intrygujący ...

19
@ R.Pate - generowanie liczb losowych nie jest zbyt przydatne, chyba że jest równomiernie rozłożone na dużą skalę
annakata

3
Przeczytaj ponownie. @David podaje tylko, jakie liczby znajdują się między granicami, a nie wynik wyboru N liczb losowych. Przyznaję, że tytuł jest mylący.
nikc.org

3
Dla przypomnienia, głosowałem zarówno na to, jak i na odpowiedzi @ jwoolard. Wybrałem tę odpowiedź jako akceptowaną odpowiedź, ponieważ przykłady jasno pokazują, dlaczego rozkład liczb jest wypaczony do liczb z większą liczbą cyfr.
Andrew Hedges

1
@ andrew-hedges ma rację - to jest jaśniejsza odpowiedź, ale dzięki :)
jwoolard

56

Twoje wyniki są rzeczywiście oczekiwane. Jeśli liczby losowe są równomiernie rozłożone w zakresie od 1 do 10 ^ n, to można oczekiwać, że około 9/10 liczb będzie miało n cyfr, a kolejne 9/100 będzie miało n-1 cyfr.


8
Dokładnie. Oczekuje się, że rozkład liczby cyfr będzie wypaczony. Rozkład liczby cyfr w dzienniku powinien być jednak jednolity.
Noldorin

45

Istnieją różne rodzaje losowości. Math.random podaje jednolity rozkład liczb.

Jeśli chcesz różnych rzędów wielkości, sugerowałbym użycie funkcji wykładniczej do utworzenia tak zwanego rozkładu prawa potęgowego :

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

Ta funkcja powinna dać mniej więcej taką samą liczbę liczb 1-cyfrowych, co liczb 2-cyfrowych i 3-cyfrowych.

Istnieją również inne rozkłady liczb losowych, takie jak rozkład normalny (zwany również rozkładem Gaussa).


Za pomocą tego algorytmu wstawiam minimum = 1i maximum = 10i czasami otrzymuję w wyniku 11. Prawdopodobnie miałeś zamiar użyć Math.floorzamiastMath.round
Sam Eaton

1
Dlaczego to działa? Czy przekształca rozkład równomierny w rozkład wykładniczy?
shinzou,

@shinzou Zapytałem na math.stackexchange i otrzymałem nieco inną formułę jako odpowiedź. Zmieniłem kod, aby odzwierciedlić matematyczną formułę z math.stackexchange.
Christian

20

Dla mnie wygląda to zupełnie przypadkowo! (Wskazówka: zależy to od przeglądarki).

Osobiście uważam, że moja implementacja byłaby lepsza, chociaż ukradłem ją z XKCD , za którą ZAWSZE należy przyznać:

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

19
+1 za wzmiankę, że jest zależny od przeglądarki, -1 za wypożyczenie xkcd bez linkowania.

Wymagane lub nie, ponieważ jest to xkcd, jest przypisywane. :)
Arafangion

2
OT: Jestem zaskoczony i szczęśliwy, że „XKCD” było odpowiedzią na pytanie w konkursie uniwersyteckim w tym tygodniu: D
Matt Sach

2
Bergi: Bezpośredni link nie wystarczy?
Arafangion

Myślę, że mają na myśli, że żart nie został poprawnie zacytowany („random = 4;” zamiast „return 4;”)
Eren Tantekin

18

Poniższy artykuł wyjaśnia, w jaki sposób math.random () w głównych przeglądarkach internetowych jest (nie) bezpieczny: „Tymczasowe śledzenie użytkowników w głównych przeglądarkach oraz wyciek informacji między domenami i ataki” autorstwa Amida Kleina (2008) . Nie jest silniejszy niż typowe funkcje PRNG wbudowane w Javę lub Windows.

Z drugiej strony implementacja SFMT okresu 2 ^ 19937-1 wymaga 2496 bajtów stanu wewnętrznego utrzymywanego dla każdej sekwencji PRNG. Niektórzy ludzie mogą uznać to za niewybaczalny koszt.


1
+1: Wspomniany artykuł jest świetny, znacznie wykraczający poza to, o czym było pierwotne pytanie.
Roland Illig

6

Jeśli używasz liczby takiej jak 10000000000000000000, wykraczasz poza dokładność typu danych używanego przez JavaScript. Zwróć uwagę, że wszystkie wygenerowane liczby kończą się na „00”.


1
Jednak w tym przypadku nie jest to jego problem.
Joey

3
@Johannes - to jeden z jego problemów :)
annakata

Dystrybucja IEE754 nie jest równa. Może potrafisz przedstawiać od 0 do 999 w przyrostach co dwa i mieć wystarczającą precyzję, aby zauważyć równomierny rozkład w tym zakresie, jeśli wybierzesz liczbę wiele razy. 10% będzie dwucyfrowe, a 90% trzycyfrowe. Kiedy jednak zaczniesz osiągać naprawdę wysokie liczby, przyrost przekroczy 1. Możesz być w stanie przejść tylko z biliona miliardów do bilionów miliardów tysięcy, a nie bilion miliardów i jeden. Chociaż w przypadku małych liczb / skal efekt ten będzie znikomy lub nie będzie istniał. Jednak efekt skali będzie miał znacznie większy wpływ.
jgmjgm

5

Wypróbowałem generator liczb pseudolosowych JS na Chaos Game .

Mój trójkąt Sierpińskiego mówi, że jest dość przypadkowy: Fraktal


2
Czy mógłbyś udostępnić tutaj kod trójkąta i jsfiddle / jsbin, abyśmy mogli łatwo sprawdzić to w praktyce dla różnych przeglądarek?
Fabrício Matté,

1
OK, ale daj mi kilka dni, bo muszę przetłumaczyć kod na angielski. Teraz jest polsko-angielski i mam dużo pracy.
zie1ony

1
@ zie1ony kilka dni już minęło.
trusktr

1
usp :( praca, praca, praca Link: kubaplas.vot.pl/green/fractal Pierwszy parametr to liczba wierzchołków. Drugi to punkt przecięcia (od 0 do 1) odcinka linii. Po prostu eksperymentuj.
zie1ony

4
Link martwy - może zamiast tego repozytorium Github?
Mark K Cowan

3

Cóż, jeśli generujesz liczby do, powiedzmy, 1e6, miejmy nadzieję, że otrzymasz wszystkie liczby z mniej więcej równym prawdopodobieństwem. Oznacza to również, że masz tylko jedną na dziesięć szans na uzyskanie liczby z jedną cyfrą mniej. Jedna na sto szans na uzyskanie dwóch cyfr mniej itd. Wątpię, czy zauważysz dużą różnicę, używając innego RNG, ponieważ masz równomierny rozkład liczb, a nie ich logarytm.


0

Liczby nielosowe równomiernie rozłożone od 1 do N mają tę samą właściwość. Zauważ, że (w pewnym sensie) jest to kwestia precyzji. Jednolity rozkład na 0-99 (jako liczby całkowite) ma 90% swoich liczb posiadających dwie cyfry. Jednolity rozkład na 0-999999 ma 905 swoich numerów posiadających pięć cyfr.

Każdy zbiór liczb (w pewnych niezbyt restrykcyjnych warunkach) ma gęstość. Kiedy ktoś chce omówić liczby „losowe”, należy określić gęstość tych liczb (jak wspomniano powyżej). Powszechną gęstością jest gęstość jednorodna. Są też inne: gęstość wykładnicza, gęstość normalna itp. Przed zaproponowaniem generatora liczb losowych należy wybrać, która gęstość jest odpowiednia. Ponadto liczby pochodzące z jednej gęstości można często łatwo przekształcić w inną gęstość za pomocą środków próchnicowych.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.