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


135

Qual è la differenza tra Math.random() * neRandom.nextInt(n) dove nè un numero intero?


Non conosco la matematica, ma so che FindBugs si lamenta se lo usiMath.random()
finnw,

3
Ricorda che Random non ha un metodo statico, quindi usa: (new Random ()). NextInt (n)). Per generare un numero intero simile, utilizzare Math: Math.floor ((Math.random () * n) +1);
Dimitri Dewaele,

Risposte:


169

Ecco la spiegazione dettagliata del perché " Random.nextInt(n)è più efficiente e meno distorto di Math.random() * n" dai post dei forum Sun a cui Gili ha collegato:

Math.random () utilizza Random.nextDouble () internamente.

Random.nextDouble () usa Random.next () due volte per generare un doppio che ha nella sua mantissa i bit distribuiti approssimativamente in modo approssimativo, quindi è distribuito uniformemente nell'intervallo da 0 a 1- (2 ^ -53).

Random.nextInt (n) usa Random.next () in media meno di due volte- lo usa una volta, e se il valore ottenuto è al di sopra del multiplo più alto di n al di sotto di MAX_INT ci riprova, altrimenti restituisce il valore modulo n (questo impedisce i valori al di sopra del multiplo più alto di n al di sotto di MAX_INT inclinando la distribuzione), quindi restituendo un valore che è distribuito uniformemente nell'intervallo da 0 a n-1.

Prima di ridimensionare di 6, l'output di Math.random () è uno dei 2 ^ 53 possibili valori tratti da una distribuzione uniforme.

Il ridimensionamento di 6 non modifica il numero di valori possibili e il casting su un int quindi forza questi valori in uno dei sei 'bucket' (0, 1, 2, 3, 4, 5), ogni bucket corrispondente agli intervalli che comprendono 1501199875790165 o 1501199875790166 dei possibili valori (poiché 6 non è un disorder di 2 ^ 53). Ciò significa che per un numero sufficiente di tiri di dado (o un dado con un numero sufficientemente ampio di lati), il dado si mostrerà distorto verso i secchi più grandi.

Aspetterai molto tempo lanciando i dadi affinché questo effetto si manifesti.

Anche Math.random () richiede circa il doppio dell'elaborazione ed è soggetto a sincronizzazione.


3
Anche Random.nextInt e nextDouble sono soggetti a sincronizzazione.
Adrianos,

In questo contesto, cosa significa "meno di parte", per favore?
ocXocę 웃 Пepeúpa ツ

2
@ ΦXocę 웃 Пepeúpa ツ Significa semplicemente che alcuni numeri hanno più probabilità di essere estratti rispetto ad altri. Come in esso è distorto la scelta di alcuni numeri rispetto ad altri (quindi non del tutto casuale o dato l'uniforme della dimensione del campione abbastanza grande)
ford prefetto

1
Si noti che l'ultimo commento a quel thread riporta: "Il bias che è stato descritto è una parte in 2 ^ 53, ma la lunghezza massima del ciclo del PRNG utilizzato è solo 2 ^ 48. Quindi ciò che vedrai nell'applicazione sono i dati distribuzione del PRNG sottostante, non del pregiudizio ". Ciò indicherebbe il fatto che i due metodi sono equivalenti
illusione digitale,

1
@ ΦXocę 웃 Пepeúpa ツ Sostituisci 6con 5su un cubo di dadi: sarà "di parte 5". Puoi lanciare i dadi un paio di volte prima di notare che qualcosa non va nei dadi. Sei costretto a eseguire un esame approfondito estremamente sofisticato prima di notare che qualcosa non va in un generatore casuale.
Dávid Horváth,

27

un altro punto importante è che Random.nextInt (n) è ripetibile poiché è possibile creare due oggetti Random con lo stesso seme. Questo non è possibile con Math.random ().



0

Secondo questo esempio Random.nextInt(n)ha un output meno prevedibile di Math.random () * n. Secondo [array ordinato più veloce di un array non ordinato] [1] Penso che possiamo dire che Random.nextInt (n) è difficile da prevedere .

usingRandomClass: tempo: 328 miglia al secondo.

usingMathsRandom: tempo: 187 miglia al secondo.

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
Nel secondo ciclo controlli> = 50, che è vero in oltre il 50% dei casi. Ciò farà sì che questa affermazione sia vera la maggior parte delle volte, il che la rende più prevedibile. I tuoi risultati sono quindi distorti a favore della tua risposta
Neuron,

è un errore di battitura ... fai 128 nel secondo esempio otterrai lo stesso risultato.
jatin Goyal,
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.