Math.random () a Random.nextInt (int)


135

Jaka jest różnica między Math.random() * ni Random.nextInt(n)gdzie njest liczba całkowita?


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.


3
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 ().



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;
public class RandomFuction 
{
    static int array[] = new int[9999];
    static long sum = 0;
    public static void 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];
                }
            }
        }
    }

    public static void usingRandomClass() {
        Random random = new Random();
        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];
                }
            }

        }

    }

    public static void 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));

    }

}

1
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.
jatin Goyal
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.