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

135

Qual é a diferença entre Math.random() * ne Random.nextInt(n)onde né um número inteiro?

Gili
fonte
Eu não sei a matemática, mas eu sei que FindBugs reclama se você usaMath.random()
finnw
3
Lembre-se de que o Random não tem método estático, então use: (new Random ()). NextInt (n)). Para o Math gerar um número inteiro semelhante, use: Math.floor ((Math.random () * n) +1);
Dimitri Dewaele

Respostas:

169

Aqui está a explicação detalhada de por que " Random.nextInt(n)é mais eficiente e menos tendencioso do que Math.random() * n" nos fóruns da Sun que Gili vinculou:

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

Random.nextDouble () usa Random.next () duas vezes para gerar um dobro que possui bits aproximadamente distribuídos uniformemente em sua mantissa, portanto, é uniformemente distribuído no intervalo de 0 a 1- (2 ^ -53).

Random.nextInt (n) usa Random.next () menos do que o dobro da média - ele o usa uma vez e, se o valor obtido estiver acima do múltiplo mais alto de n abaixo de MAX_INT, ele tentará novamente, caso contrário, retornará o valor módulo n (este impede que os valores acima do múltiplo mais alto de n abaixo de MAX_INT incline a distribuição), retornando um valor uniformemente distribuído no intervalo de 0 a n-1.

Antes da escala de 6, a saída de Math.random () é um dos 2 ^ 53 valores possíveis extraídos de uma distribuição uniforme.

O escalonamento por 6 não altera o número de valores possíveis e a conversão para um int força esses valores a um dos seis 'buckets' (0, 1, 2, 3, 4, 5), cada bucket correspondente a intervalos que abrangem 1501199875790165 ou 1501199875790166 dos valores possíveis (como 6 não é um disvisor de 2 ^ 53). Isso significa que, para um número suficiente de jogadas de dados (ou um dado com um número suficientemente grande de lados), o dado se mostrará inclinado para os baldes maiores.

Você estará esperando muito tempo rolando dados para que esse efeito apareça.

Math.random () também requer aproximadamente o dobro do processamento e está sujeito a sincronização.

matt b
fonte
3
Random.nextInt e nextDouble também estão sujeitos à sincronização.
Adrianos
Nesse contexto, o que significa "menos tendencioso", por favor?
ΦXocę П pepeúpa
2
@ OcXocę 웃 pepeúpa ツ Simplesmente significa que certos números têm mais probabilidade de serem sorteados do que outros. Como nele é inclinado para escolher alguns números sobre os outros (portanto não totalmente aleatória ou dada grande tamanho uniforme suficiente amostra)
vau prefeito
1
Observe que o último comentário desse segmento informa: "O viés descrito é uma parte em 2 ^ 53, mas a duração máxima do ciclo do PRNG usado é de apenas 2 ^ 48. Portanto, o que você verá no aplicativo são os dados distribuição do PRNG subjacente, não o viés ". Isso aponta para o fato de que os dois métodos são equivalentes
ilusão digital de
1
@ ΦXocę 웃 ПepeúpaツSubstituir 6com 5em um cubo dados: será "5-tendenciosa". Você pode jogar os dados algumas vezes antes de perceber que algo está errado com os dados. Você é forçado a realizar um exame completo extremamente sofisticado antes de perceber que algo está errado com um gerador aleatório.
Dávid Horváth
27

Outro ponto importante é que Random.nextInt (n) é repetível, pois você pode criar dois objetos Random com a mesma semente. Isso não é possível com Math.random ().

dfa
fonte
0

De acordo com este exemplo Random.nextInt(n), a saída é menos previsível do que Math.random () * n. De acordo com [matriz ordenada mais rapidamente que uma matriz não classificada] [1], acho que podemos dizer que Random.nextInt (n) é difícil de prever .

usingRandomClass: time: 328 milhasecond.

usingMathsRandom: time: 187 milesecond.

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));

    }

}
jatin Goyal
fonte
1
No segundo loop, você verifica> = 50, o que é verdade em mais de 50% dos casos. Isso fará com que essa declaração if seja verdadeira na maioria das vezes, o que a torna mais previsível. Seus resultados são, portanto, tendenciosa em favor de sua resposta
Neuron
é erro de digitação ... faça 128 no segundo exemplo, você obterá o mesmo resultado.
Jatin Goyal