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

135

Quelle est la différence entre Math.random() * net Random.nextInt(n)nest un entier?

Gili
la source
Je ne connais pas le calcul, mais je sais que FindBugs se plaint si vous utilisezMath.random()
finnw
3
N'oubliez pas que Random n'a pas de méthode statique, utilisez donc: (new Random ()). NextInt (n)). Pour que Math génère un entier similaire, utilisez: Math.floor ((Math.random () * n) +1);
Dimitri Dewaele

Réponses:

169

Voici l'explication détaillée de la raison pour laquelle " Random.nextInt(n)est à la fois plus efficace et moins biaisé que Math.random() * n" dans le post des forums Sun auquel Gili a lié:

Math.random () utilise Random.nextDouble () en interne.

Random.nextDouble () utilise Random.next () deux fois pour générer un double qui a des bits distribués à peu près uniformément dans sa mantisse, de sorte qu'il est uniformément distribué dans la plage de 0 à 1- (2 ^ -53).

Random.nextInt (n) utilise Random.next () moins de deux fois en moyenne - il l'utilise une fois, et si la valeur obtenue est au-dessus du multiple le plus élevé de n en dessous de MAX_INT il essaie à nouveau, sinon il renvoie la valeur modulo n (ce empêche les valeurs au-dessus du multiple le plus élevé de n en dessous de MAX_INT de biaiser la distribution), renvoyant ainsi une valeur uniformément distribuée dans la plage de 0 à n-1.

Avant la mise à l'échelle par 6, la sortie de Math.random () est l'une des 2 ^ 53 valeurs possibles tirées d'une distribution uniforme.

La mise à l'échelle par 6 ne modifie pas le nombre de valeurs possibles, et la conversion en un int force alors ces valeurs dans l'un des six `` compartiments '' (0, 1, 2, 3, 4, 5), chaque compartiment correspondant à des plages englobant soit 1501199875790165 ou 1501199875790166 des valeurs possibles (car 6 n'est pas un disvisor de 2 ^ 53). Cela signifie que pour un nombre suffisant de jets de dés (ou un dé avec un nombre de faces suffisamment grand), le dé se montrera biaisé vers les plus grands seaux.

Vous attendez très longtemps de lancer des dés pour que cet effet se manifeste.

Math.random () nécessite également environ deux fois le traitement et est soumis à la synchronisation.

mat b
la source
3
Random.nextInt et nextDouble sont également soumis à la synchronisation.
adrianos
Dans ce contexte, que signifie "moins biaisé", s'il vous plaît?
ΦXocę 웃 Пepeúpa ツ
2
@ ΦXocę 웃 Пepeúpa ツ Cela signifie simplement que certains nombres sont plus susceptibles d'être tirés que d'autres. Comme dans le cas, il est biaisé de choisir certains nombres par rapport à d'autres (donc pas totalement aléatoires ou avec une taille d'échantillon suffisamment large)
ford prefect
1
Notez que le dernier commentaire à ce fil rapporte: "Le biais qui a été décrit est une partie sur 2 ^ 53, mais la longueur maximale du cycle du PRNG utilisé n'est que de 2 ^ 48. Ce que vous verrez dans l'application, ce sont les données distribution du PRNG sous-jacent, pas le biais. " Cela indiquerait le fait que les deux méthodes sont équivalentes
illusion numérique
1
@ ΦXocę 웃 Пepeúpa ツ Remplacez 6par 5sur un cube de dés: il sera "5 biaisé". Vous pouvez lancer les dés plusieurs fois avant de remarquer que quelque chose ne va pas avec les dés. Vous êtes obligé d'effectuer un examen approfondi extrêmement sophistiqué avant de remarquer que quelque chose ne va pas avec un générateur aléatoire.
Dávid Horváth
27

un autre point important est que Random.nextInt (n) est répétable puisque vous pouvez créer deux objets Random avec la même graine. Ce n'est pas possible avec Math.random ().

dfa
la source
0

Selon cet exemple, la Random.nextInt(n)sortie est moins prévisible que Math.random () * n. Selon [tableau trié plus rapidement qu'un tableau non trié] [1] je pense que nous pouvons dire que Random.nextInt (n) est difficile à prédire .

usingRandomClass: temps: 328 milesecondes.

usingMathsRandom: temps: 187 milesecondes.

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
la source
1
Dans la deuxième boucle, vous vérifiez> = 50, ce qui est vrai dans plus de 50% des cas. Cela rendra cette déclaration si vraie la plupart du temps, ce qui la rend plus prévisible. Vos résultats sont donc biaisés en faveur de votre réponse
Neuron
c'est une faute de frappe ... faites 128 dans le deuxième exemple, vous obtiendrez le même résultat.
jatin Goyal