Question Comment générer des entiers aléatoires dans une plage spécifique en Java?


Comment puis-je générer un aléatoire int valeur dans une gamme spécifique?

J'ai essayé ce qui suit, mais ceux qui ne fonctionnent pas:

Tentative 1:

randomNum = minimum + (int)(Math.random() * maximum);
// Bug: `randomNum` can be bigger than `maximum`.

Tentative 2:

Random rn = new Random();
int n = maximum - minimum + 1;
int i = rn.nextInt() % n;
randomNum =  minimum + i;
// Bug: `randomNum` can be smaller than `minimum`.

2897
2017-12-12 18:20


origine


Réponses:


Dans Java 1.7 ou plus tard, la façon standard de le faire est la suivante:

import java.util.concurrent.ThreadLocalRandom;

// nextInt is normally exclusive of the top value,
// so add 1 to make it inclusive
int randomNum = ThreadLocalRandom.current().nextInt(min, max + 1);

Voir le JavaDoc pertinent. Cette approche a l'avantage de ne pas avoir besoin d'initialiser explicitement java.util.Random exemple, qui peut être une source de confusion et d'erreur si elle est utilisée de manière inappropriée.

Cependant, inversement, il n'y a aucun moyen de définir explicitement la graine de sorte qu'il peut être difficile de reproduire les résultats dans des situations où cela est utile, comme par exemple tester ou sauvegarder des états de jeu ou similaires. Dans ces situations, la technique pré-Java 1.7 ci-dessous peut être utilisée.

Avant Java 1.7, la façon standard de le faire est la suivante:

import java.util.Random;

/**
 * Returns a pseudo-random number between min and max, inclusive.
 * The difference between min and max can be at most
 * <code>Integer.MAX_VALUE - 1</code>.
 *
 * @param min Minimum value
 * @param max Maximum value.  Must be greater than min.
 * @return Integer between min and max, inclusive.
 * @see java.util.Random#nextInt(int)
 */
public static int randInt(int min, int max) {

    // NOTE: This will (intentionally) not run as written so that folks
    // copy-pasting have to think about how to initialize their
    // Random instance.  Initialization of the Random instance is outside
    // the main scope of the question, but some decent options are to have
    // a field that is initialized once and then re-used as needed or to
    // use ThreadLocalRandom (if using at least Java 1.7).
    // 
    // In particular, do NOT do 'Random rand = new Random()' here or you
    // will get not very good / not very random results.
    Random rand;

    // nextInt is normally exclusive of the top value,
    // so add 1 to make it inclusive
    int randomNum = rand.nextInt((max - min) + 1) + min;

    return randomNum;
}

Voir le JavaDoc pertinent. En pratique, le java.util.Random classe est souvent préférable à java.lang.Math.random ().

En particulier, il n'est pas nécessaire de réinventer la roue de génération d'entier aléatoire quand il y a une API simple dans la bibliothèque standard pour accomplir la tâche.


3254
2017-12-12 18:25



Notez que cette approche est plus biaisée et moins efficace qu'une nextInt approche, https://stackoverflow.com/a/738651/360211

Un modèle standard pour accomplir ceci est:

Min + (int)(Math.random() * ((Max - Min) + 1))

le Java La fonction de bibliothèque mathématique Math.random () génère une double valeur dans la plage [0,1). Notez que cette plage n'inclut pas le 1.

Pour obtenir une plage de valeurs spécifique en premier, vous devez multiplier par l'amplitude de la plage de valeurs que vous souhaitez couvrir.

Math.random() * ( Max - Min )

Cela renvoie une valeur dans la plage [0,Max-Min), où 'Max-Min' n'est pas inclus.

Par exemple, si vous voulez [5,10), vous devez couvrir cinq valeurs entières de sorte que vous utilisez

Math.random() * 5

Cela retournera une valeur dans la plage [0,5), où 5 n'est pas inclus.

Vous devez maintenant déplacer cette plage vers la plage que vous ciblez. Vous faites cela en ajoutant la valeur Min.

Min + (Math.random() * (Max - Min))

Vous allez maintenant avoir une valeur dans la plage [Min,Max). En suivant notre exemple, cela signifie [5,10):

5 + (Math.random() * (10 - 5))

Mais, cela ne comprend toujours pas Max et vous obtenez une double valeur. Afin d'obtenir le Max valeur incluse, vous devez ajouter 1 à votre paramètre de plage (Max - Min) puis tronquez la partie décimale en la transtypant dans un int. Ceci est accompli via:

Min + (int)(Math.random() * ((Max - Min) + 1))

Et voila. Une valeur entière aléatoire dans la plage [Min,Max]ou par l'exemple [5,10]:

5 + (int)(Math.random() * ((10 - 5) + 1))

1323
2017-12-12 18:35



Utilisation:

Random ran = new Random();
int x = ran.nextInt(6) + 5;

L'entier x est maintenant le nombre aléatoire qui a un résultat possible de 5-10.


311
2017-09-04 04:23



Utilisation:

minimum + rn.nextInt(maxValue - minvalue + 1)

122
2017-12-12 18:25



Avec  ils ont introduit la méthode ints(int randomNumberOrigin, int randomNumberBound) dans le Random classe.

Par exemple, si vous voulez générer cinq entiers aléatoires (ou un seul) dans la plage [0, 10], faites simplement:

Random r = new Random();
int[] fiveRandomNumbers = r.ints(5, 0, 11).toArray();
int randomNumber = r.ints(1, 0, 11).findFirst().getAsInt();

Le premier paramètre indique seulement la taille du IntStream généré (qui est la méthode surchargée de celle qui produit un nombre illimité IntStream).

Si vous devez effectuer plusieurs appels distincts, vous pouvez créer un itérateur primitif infini à partir du flux:

public final class IntRandomNumberGenerator {

    private PrimitiveIterator.OfInt randomIterator;

    /**
     * Initialize a new random number generator that generates
     * random numbers in the range [min, max]
     * @param min - the min value (inclusive)
     * @param max - the max value (inclusive)
     */
    public IntRandomNumberGenerator(int min, int max) {
        randomIterator = new Random().ints(min, max + 1).iterator();
    }

    /**
     * Returns a random number in the range (min, max)
     * @return a random number in the range (min, max)
     */
    public int nextInt() {
        return randomIterator.nextInt();
    }
}

Vous pouvez aussi le faire pour double et long valeurs.

J'espère que cela aide! :)


98
2017-11-26 18:29



Vous pouvez modifier votre deuxième exemple de code pour:

Random rn = new Random();
int range = maximum - minimum + 1;
int randomNum =  rn.nextInt(range) + minimum;

90
2017-12-12 18:31



Juste une petite modification de votre première solution suffirait.

Random rand = new Random();
randomNum = minimum + rand.nextInt((maximum - minimum) + 1);

Voir plus ici pour la mise en œuvre de Random


89
2018-03-12 22:44



ThreadLocalRandom équivalent de la classe java.util.Random pour un environnement multithread. La génération d'un nombre aléatoire est effectuée localement dans chacun des threads. Nous avons donc une meilleure performance en réduisant les conflits.

int rand = ThreadLocalRandom.current().nextInt(x,y);

x, y - intervalles, par ex. (1,10)


54
2018-02-12 23:19



le Math.Random classe dans Java est basé sur 0. Donc, si vous écrivez quelque chose comme ceci:

Random rand = new Random();
int x = rand.nextInt(10);

x sera entre 0-9 compris.

Donc, étant donné le tableau suivant de 25 éléments, le code pour générer un nombre aléatoire entre 0 (la base du tableau) et array.length serait:

String[] i = new String[25];
Random rand = new Random();
int index = 0;

index = rand.nextInt( i.length );

Depuis i.length reviendra 25, la nextInt( i.length ) retournera un nombre entre la gamme de 0-24. L'autre option va avec Math.Random qui fonctionne de la même manière.

index = (int) Math.floor(Math.random() * i.length);

Pour une meilleure compréhension, consultez le post du forum Intervalles aléatoires (archive.org).


53
2018-01-08 15:04



Pardonnez-moi d'être méticuleux, mais la solution suggérée par la majorité, c'est-à-dire, min + rng.nextInt(max - min + 1)), semble périlleux en raison du fait que:

  • rng.nextInt(n) ne peut pas atteindre Integer.MAX_VALUE.
  • (max - min) peut provoquer un débordement lorsque min est négatif.

Une solution infaillible renverrait des résultats corrects pour tout min <= max dans [Integer.MIN_VALUE, Integer.MAX_VALUE] Considérez l'implémentation naïve suivante:

int nextIntInRange(int min, int max, Random rng) {
   if (min > max) {
      throw new IllegalArgumentException("Cannot draw random int from invalid range [" + min + ", " + max + "].");
   }
   int diff = max - min;
   if (diff >= 0 && diff != Integer.MAX_VALUE) {
      return (min + rng.nextInt(diff + 1));
   }
   int i;
   do {
      i = rng.nextInt();
   } while (i < min || i > max);
   return i;
}

Bien qu'inefficace, notez que la probabilité de succès dans le while la boucle sera toujours 50% ou plus.


43
2018-01-10 13:19