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.
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 ().
Eu recomendaria realmente citar parte de seu post e resumir um pouco aqui. O link deve ser complementar à sua resposta.
jjnguy
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;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));}}
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.
Math.random()
Respostas:
Aqui está a explicação detalhada de por que "
Random.nextInt(n)
é mais eficiente e menos tendencioso do queMath.random() * n
" nos fóruns da Sun que Gili vinculou:fonte
6
com5
em 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.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 ().
fonte
De acordo com https://forums.oracle.com/forums/thread.jspa?messageID=6594485�,
Random.nextInt(n)
é mais eficiente e menos tendencioso do queMath.random() * n
fonte
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.
fonte