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

135

¿Cuál es la diferencia entre Math.random() * ny Random.nextInt(n)dónde nestá un número entero?

Gili
fuente
No sé las matemáticas, pero sé que FindBugs se queja si usasMath.random()
finnw
3
Recuerde que Random no tiene un método estático, así que use: (new Random ()). NextInt (n)). Para que Math genere un número entero similar use: Math.floor ((Math.random () * n) +1);
Dimitri Dewaele

Respuestas:

169

Aquí está la explicación detallada de por qué " Random.nextInt(n)es más eficiente y menos sesgado que Math.random() * n" de la publicación en los foros de Sun a la que Gili se vinculó:

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

Random.nextDouble () usa Random.next () dos veces para generar un doble que tiene bits distribuidos aproximadamente uniformemente en su mantisa, por lo que se distribuye uniformemente en el rango de 0 a 1- (2 ^ -53).

Random.nextInt (n) usa Random.next () menos de dos veces en promedio, lo usa una vez, y si el valor obtenido está por encima del múltiplo más alto de n por debajo de MAX_INT lo intenta nuevamente; de ​​lo contrario, devuelve el valor módulo n (esto evita que los valores por encima del múltiplo más alto de n por debajo de MAX_INT sesguen la distribución), por lo que devuelve un valor que se distribuye uniformemente en el rango de 0 a n-1.

Antes de escalar en 6, la salida de Math.random () es uno de los 2 ^ 53 posibles valores extraídos de una distribución uniforme.

Escalar en 6 no altera el número de valores posibles, y la conversión a un int obliga a estos valores a uno de los seis 'cubos' (0, 1, 2, 3, 4, 5), cada cubo corresponde a rangos que abarcan 1501199875790165 o 1501199875790166 de los posibles valores (ya que 6 no es un supervisor de 2 ^ 53). Esto significa que para un número suficiente de tiradas de dados (o un dado con un número suficientemente grande de lados), el dado se mostrará sesgado hacia los cubos más grandes.

Esperarás mucho tiempo tirando dados para que aparezca este efecto.

Math.random () también requiere aproximadamente el doble del procesamiento y está sujeto a sincronización.

mate b
fuente
3
Random.nextInt y nextDouble también están sujetos a sincronización.
adrianos
En este contexto, ¿qué significa "menos sesgado", por favor?
ΦXocę 웃 Пepeúpa ツ
2
@ ΦXocę 웃 Пepeúpa ツ Simplemente significa que es más probable que se dibujen ciertos números que otros. Como está sesgado a elegir algunos números sobre otros (por lo tanto, no es totalmente aleatorio ni se le da un tamaño de muestra lo suficientemente uniforme)
prefecto
1
Tenga en cuenta que el último comentario a ese hilo informa: "El sesgo que se describió es una parte en 2 ^ 53, pero la duración máxima del ciclo del PRNG utilizado es solo 2 ^ 48. Entonces, lo que verá en la aplicación son los datos distribución del PRNG subyacente, no el sesgo ". Esto apuntaría al hecho de que los dos métodos son equivalentes
ilusión digital el
1
@ ΦXocę 웃 Пepeúpa ツ Reemplazar 6con 5en un cubo de dados: será "5 parcial". Puedes lanzar los dados un par de veces antes de notar que algo está mal con los dados. Se ve obligado a realizar un examen exhaustivo extremadamente sofisticado antes de notar que algo anda mal con un generador aleatorio.
Dávid Horváth
27

Otro punto importante es que Random.nextInt (n) es repetible ya que puede crear dos objetos aleatorios con la misma semilla. Esto no es posible con Math.random ().

dfa
fuente
0

De acuerdo con este ejemplo, Random.nextInt(n)tiene una salida menos predecible que Math.random () * n. Según [matriz ordenada más rápido que una matriz sin clasificar] [1] creo que podemos decir que Random.nextInt (n) es difícil de predecir .

usingRandomClass: tiempo: 328 millas por segundo.

usingMathsRandom: tiempo: 187 millas por segundo.

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
fuente
1
En el segundo ciclo, verifica> = 50, lo cual es cierto en más del 50% de los casos. Eso hará que esta afirmación sea cierta la mayoría de las veces, lo que la hace más predecible. Por lo tanto, sus resultados están sesgados a favor de su respuesta
Neuron
es un error tipográfico ... haga 128 en el segundo ejemplo obtendrá el mismo resultado.
jatin Goyal