Nie znam matematyki, ale wiem, że FindBugs narzeka, jeśli używaszMath.random()
finnw
3
Pamiętaj, że Random nie ma metody statycznej, więc użyj: (new Random ()). NextInt (n)). Aby Math wygenerował podobną liczbę całkowitą, użyj: Math.floor ((Math.random () * n) +1);
Dimitri Dewaele
Odpowiedzi:
169
Oto szczegółowe wyjaśnienie, dlaczego „ Random.nextInt(n)jest zarówno bardziej wydajne, jak i mniej stronnicze niż Math.random() * n” z postu na forach firmy Sun, do którego prowadzi Gili:
Math.random () używa Random.nextDouble () wewnętrznie.
Random.nextDouble () używa Random.next () dwukrotnie, aby wygenerować double, który ma w przybliżeniu równomiernie rozłożone bity w mantysie, więc jest równomiernie rozłożony w zakresie od 0 do 1- (2 ^ -53).
Random.nextInt (n) używa Random.next () średnio mniej niż dwa razy - używa go raz, a jeśli uzyskana wartość jest powyżej najwyższej wielokrotności n poniżej MAX_INT, próbuje ponownie, w przeciwnym razie zwraca wartość modulo n (to zapobiega przekrzywianiu rozkładu wartości powyżej najwyższej wielokrotności n poniżej wartości MAX_INT), w związku z czym zwraca wartość, która jest równomiernie rozłożona w zakresie od 0 do n-1.
Przed skalowaniem o 6 wynik funkcji Math.random () jest jedną z 2 ^ 53 możliwych wartości pobranych z rozkładu równomiernego.
Skalowanie o 6 nie zmienia liczby możliwych wartości, a rzutowanie na int następnie wymusza te wartości w jednym z sześciu „przedziałów” (0, 1, 2, 3, 4, 5), z których każdy odpowiada zakresom obejmującym albo 1501199875790165 lub 1501199875790166 z możliwych wartości (ponieważ 6 nie jest doradcą 2 ^ 53). Oznacza to, że przy wystarczającej liczbie rzutów kośćmi (lub kości z dostatecznie dużą liczbą boków), kość okaże się odchylona w kierunku większych koszy.
Będziesz bardzo długo czekać, aż ten efekt się pojawi.
Math.random () również wymaga około dwukrotnie większego przetwarzania i podlega synchronizacji.
Synchronizacji podlegają również Random.nextInt i nextDouble.
adrianos
Co w tym kontekście oznacza „mniej stronniczy”?
ΦXocę 웃 Пepeúpa ツ
2
@ ΦXocę 웃 Пepeúpa ツ Oznacza to po prostu, że niektóre liczby mają większe szanse na wylosowanie niż inne. Ponieważ jest tendencyjny do wybierania niektórych liczb w stosunku do innych (stąd nie jest całkowicie losowy lub ma jednolity rozmiar próbki)
ford prefect
1
Zwróć uwagę, że ostatni komentarz do tego wątku informuje: „Opisane odchylenie jest jedną częścią w 2 ^ 53, ale maksymalna długość cyklu używanego PRNG to tylko 2 ^ 48. Więc to, co zobaczysz w aplikacji, to dane dystrybucja bazowego PRNG, a nie stronniczość. " To wskazywałoby na fakt, że te dwie metody są równoważne
iluzja cyfrowa
1
@ ΦXocę 웃 ПepeúpaツWymień 6ze 5na sześcian: będzie to „5-tendencyjne”. Możesz rzucić kostką kilka razy, zanim zauważysz, że coś jest nie tak z kostką. Jesteś zmuszony przeprowadzić niezwykle wyrafinowane, dokładne badanie, zanim zauważysz, że coś jest nie tak z generatorem losowym.
Dávid Horváth
27
kolejną ważną kwestią jest to, że Random.nextInt (n) jest powtarzalne, ponieważ możesz utworzyć dwa obiekty Random za pomocą samym ziarnem. Nie jest to możliwe z Math.random ().
Poleciłbym właściwie zacytować część jego postu i podsumować trochę tutaj. Link powinien być uzupełnieniem Twojej odpowiedzi.
jjnguy
0
Zgodnie z tym przykładem Random.nextInt(n)ma mniej przewidywalne wyniki niż Math.random () * n. Zgodnie z [posortowana tablica szybciej niż nieposortowana tablica] [1] Myślę, że możemy powiedzieć, że Random.nextInt (n) jest trudna do przewidzenia .
usingRandomClass: time: 328 milecond.
usingMathsRandom: time: 187 milekund.
package javaFuction;import java.util.Random;publicclassRandomFuction{staticint array[]=newint[9999];staticlong sum =0;publicstaticvoid usingMathsRandom(){for(int i =0; i <9999; i++){
array[i]=(int)(Math.random()*256);}for(int i =0; i <9999; i++){for(int j =0; j <9999; j++){if(array[j]>=128){
sum += array[j];}}}}publicstaticvoid usingRandomClass(){Random random =newRandom();for(int i =0; i <9999; i++){
array[i]= random.nextInt(256);}for(int i =0; i <9999; i++){for(int j =0; j <9999; j++){if(array[j]>=128){
sum += array[j];}}}}publicstaticvoid main(String[] args){long start =System.currentTimeMillis();
usingRandomClass();long end =System.currentTimeMillis();System.out.println("usingRandomClass "+(end - start));
start =System.currentTimeMillis();
usingMathsRandom();
end =System.currentTimeMillis();System.out.println("usingMathsRandom "+(end - start));}}
W drugiej pętli sprawdzasz> = 50, co jest prawdą w ponad 50% przypadków. To spowoduje, że stwierdzenie to będzie prawdziwe w większości przypadków, co czyni je bardziej przewidywalnymi. Twoje wyniki są zatem tendencyjne na korzyść Twojej odpowiedzi
Neuron,
to pomyłka ... zrób 128 w drugim przykładzie otrzymasz ten sam wynik.
Math.random()
Odpowiedzi:
Oto szczegółowe wyjaśnienie, dlaczego „
Random.nextInt(n)
jest zarówno bardziej wydajne, jak i mniej stronnicze niżMath.random() * n
” z postu na forach firmy Sun, do którego prowadzi Gili:źródło
6
ze5
na sześcian: będzie to „5-tendencyjne”. Możesz rzucić kostką kilka razy, zanim zauważysz, że coś jest nie tak z kostką. Jesteś zmuszony przeprowadzić niezwykle wyrafinowane, dokładne badanie, zanim zauważysz, że coś jest nie tak z generatorem losowym.kolejną ważną kwestią jest to, że Random.nextInt (n) jest powtarzalne, ponieważ możesz utworzyć dwa obiekty Random za pomocą samym ziarnem. Nie jest to możliwe z Math.random ().
źródło
Według https://forums.oracle.com/forums/thread.jspa?messageID=6594485龵
Random.nextInt(n)
jest zarówno bardziej wydajny, jak i mniej stronniczy niżMath.random() * n
źródło
Zgodnie z tym przykładem
Random.nextInt(n)
ma mniej przewidywalne wyniki niż Math.random () * n. Zgodnie z [posortowana tablica szybciej niż nieposortowana tablica] [1] Myślę, że możemy powiedzieć, że Random.nextInt (n) jest trudna do przewidzenia .usingRandomClass: time: 328 milecond.
usingMathsRandom: time: 187 milekund.
źródło