Petite explication sur base d'une recherche Google me renseignant un article chez ''stackoverflow'' . Je cite

Math.random() uses Random.nextDouble() internally.

Random.nextDouble() uses Random.next() twice to generate a double that has approximately uniformly distributed bits in its mantissa, so it is uniformly distributed in the range 0 to 1-(2^-53).

Extrait de stackoverflow.com

screenshot-random-next-1.png

Comment puis-je vérifier ces assertions ?

Math.random() utilise nextDouble()

Simplement en prenant la peine de télécharger les sources de mon jdk et en les décompressant (c'est sans doute une belle illustration de ce que c'est que l'open source). J'obtiens un répertoire à l'allure suivante.

J'édite le fichier java/lang/Math.java [1] et cherche le code qui m'intéresse pour constater que c'est, effectivement, un simple appel à la méthode nextDouble d'un objet Random

private static Random randomNumberGenerator;
 
private static synchronized void initRNG() {
        if (randomNumberGenerator == null)
            randomNumberGenerator = new Random();
}
 
public static double random() {
        if (randomNumberGenerator == null) initRNG();
        return randomNumberGenerator.nextDouble();
}

Je constate également que la méthode Math.random() utilise le même objet Random pour tous les appels à la méthode Math.random() (l'objet est initialisé lors du premier appel).

Que fait Random.nextDouble()

Que fait Random.nextDouble()[2] [3] ?

public double nextDouble() {
      return (((long)(next(26)) << 27) + next(27))
   	/ (double)(1L << 53);
}

La méthode next(int) est la méthode permettant d'obtenir un nombre aléatoire. Son paramètre représente la taille (en bits) du nombre aléatoire que l'on recevra.

Par exemple, si vous faites moults appels comme next(2), vous ne recevrez que des valeurs parmis; 0, 1, 2 et 3.

L'opérateur << permet de faire un shift de n bits vers la gauche ((re)lire à ce sujet Langage specifications, section 15.19, page 502 (536 du PDF )).

On pourrait simplement regarder passer ou bien mettre les doigts dedans ...

Mettons (superficiellement) les doigts dedans ... mais avant, une lecture de Wikipedia (ou des pages 37 à 40 -71 à 74 du PDF- "Language specifications") expliquant la norme IEEE 754 de représentation des nombres en virgule flottante ... est plus que conseillée.

... quelques instants plus tard ...

Je comprend maintenant d'ou viennent les valeurs 26, 27 et 53 et (plus ou moins) comment est générée cette valeur double aléatoire.

Quid de la génération d'un entier en utilisant la classe Random ?

Random.nextInt(n) uses Random.next() less than twice on average- it uses it once, and if the value obtained is above the highest multiple of n below MAX_INT it tries again, otherwise is returns the value modulo n (this prevents the values above the highest multiple of n below MAX_INT skewing the distribution), so returning a value which is uniformly distributed in the range 0 to n-1.

Si Random.nextInt() est très simple à comprendre puisqu'il me génère une suite de 32 bits "aléatoires", Random.nextInt(n) est plus complexe. Si je comprend bien, prendre le modulo d'une valeur "trop grande" risque de biaiser la suite de nombres aléatoires[4].

public int nextInt() {
	return next(32);
}
public int nextInt(int n) {
     if (n <= 0)
         throw new IllegalArgumentException("n must be positive");
 
    if ((n & -n) == n)  // i.e., n is a power of 2
         return (int)((n * (long)next(31)) >> 31);
 
    int bits, val;
     do {
         bits = next(31);
         val = bits % n;
     } while (bits - val + (n-1) < 0);
     return val;
}

Une autre remarque que l'on peut faire est que Random.next() permet de regénérer deux fois la même suite de nombres aléatoires. Il suffit de choisir la même graine (seed). Ce qui n'est pas possible avec Math.random() puisque la graine n'est pas précisée lors de l'initialisation de Random dans la méthode initRNG.

Another important point is that Random.nextInt(n) is repeatable since you can create two Random object with the same seed. This is not possible with Math.random().

Extrait de stackoverflow.com

Le fait de pouvoir générer plusieurs fois la même séquence de nombres peut-être intéressant lors de la mise au point d'un programme et/ou lors de tests.

En espérant que ceci vous a éclairé ...

À lire aussi

Notes

[1] Comme c'est facile de le trouver dans tous ces fichiers puisque son emplacement correspond au nom de son package

[2] Remarquez que je n'ai pas touché à l'indentation du code et je vois que les conventions d'écriture du code (voir le document Conventions d'écriture du code en Java REF) sont respectées: break before operator

[3] Remarquez également (si vous allez voir ce code) qu'il est également visible dans la javadoc. Les sources sont danc inutiles dans ce cas ... sauf pour vérifier que le code correspond à la doc ^^

[4] Ce n'est pas tout à fait clair dans ma tête, un passant peu nous éclairer, mais je n'y passe pas plus de temps maintenant