web-dev-qa-db-fra.com

Java: nombre long aléatoire dans une plage <= x <n

La classe aléatoire a une méthode pour générer un int aléatoire dans une plage donnée. Par exemple:

Random r = new Random(); 
int x = r.nextInt(100);

Cela générerait un nombre entier supérieur ou égal à 0 et inférieur à 100. J'aimerais faire exactement la même chose avec un nombre long.

long y = magicRandomLongGenerator(100);

La classe aléatoire a seulement nextLong (), mais elle ne permet pas de définir la plage.

112
Vilius Normantas

À partir de Java 7 (ou de l'API Android Niveau 21 = 5.0+), vous pouvez directement utiliser ThreadLocalRandom.current().nextLong(n) (pour 0 ≤ x <n) et ThreadLocalRandom.current().nextLong(m, n) (pour m ≤ x <n). Voir la réponse de @Alex pour plus de détails.


Si vous êtes coincé avec Java 6 (ou Android 4.x), vous devez utiliser une bibliothèque externe (par exemple, org.Apache.commons.math3.random.RandomDataGenerator.getRandomGenerator().nextLong(0, n-1), voir la réponse de @mawaldne ) ou implémenter votre propre nextLong(n).

Selon http://Java.Sun.com/j2se/1.5.0/docs/api/Java/util/Random.htmlnextInt est implémenté en tant que

 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;
 }

Nous pouvons donc modifier ceci pour effectuer nextLong:

long nextLong(Random rng, long n) {
   // error checking and 2^x checking removed for simplicity.
   long bits, val;
   do {
      bits = (rng.nextLong() << 1) >>> 1;
      val = bits % n;
   } while (bits-val+(n-1) < 0L);
   return val;
}
131
kennytm

La méthode standard pour générer un nombre (sans méthode d'utilité) dans une plage consiste à utiliser simplement le double avec la plage:

long range = 1234567L;
Random r = new Random()
long number = (long)(r.nextDouble()*range);

vous donnera un long entre 0 (inclus) et range (exclusif). De même si vous voulez un nombre compris entre x et y:

long x = 1234567L;
long y = 23456789L;
Random r = new Random()
long number = x+((long)(r.nextDouble()*(y-x)));

vous donnera un long de 1234567 (inclus) à 123456789 (exclusif)

Remarque: vérifiez les parenthèses, car la conversion en long est plus prioritaire que la multiplication.

73
M. Jessup

ThreadLocalRandom

ThreadLocalRandom a une méthode - nextLong(long bound) .

long v = ThreadLocalRandom.current().nextLong(100);

Il a également nextLong(long Origin, long bound) si vous avez besoin d’une origine autre que 0. Transmettez l’origine (incluse) et la borne (exclusive).

long v = ThreadLocalRandom.current().nextLong(10,100); // For 2-digit integers, 10-99 inclusive.

SplittableRandom a les mêmes méthodes nextLong et vous permet de choisir une graine si vous voulez une séquence de nombres reproductible.

59
Alex

Les méthodes ci-dessus fonctionnent très bien. Si vous utilisez Apache commons (org.Apache.commons.math.random), consultez RandomData. Il a une méthode: nextLong (long inférieur, long supérieur) 

http://commons.Apache.org/math/userguide/random.html

http://commons.Apache.org/math/api-1.1/org/Apache/commons/math/random/RandomData.html#nextLong(long,%20long)

12
mawaldne

Utilisez l'opérateur '%'

resultingNumber = (r.nextLong() % (maximum - minimum)) + minimum;

En utilisant l'opérateur '%', nous prenons le reste divisé par votre valeur maximale. Cela ne nous laisse que des nombres allant de 0 (inclus) au diviseur (exclusif).

Par exemple:

public long randLong(long min, long max) {
    return (new Java.util.Random().nextLong() % (max - min)) + min;
}
10
Septic Overflow

Merci beaucoup pour ce post. C'est juste ce dont j'avais besoin. J'ai dû changer quelque chose pour obtenir la partie sur laquelle je travaillais.

J'ai eu ce qui suit (inclus ci-dessus):

long number = x+((long)r.nextDouble()*(y-x));

travailler en le changeant pour:

long number = x+ (long)(r.nextDouble()*(y-x));

puisque (long)r.nextDouble() est toujours zéro.

2
Cece

Si vous voulez un pseudo-aléatoire long uniformément réparti dans la plage de [0, m), essayez d’utiliser l’opérateur modulo et la méthode de valeur absolue combinée à la méthode nextLong() comme indiqué ci-dessous:

Math.abs(Rand.nextLong()) % m;

Rand est votre objet aléatoire.

L'opérateur modulo divise deux nombres et sort le reste de ces nombres. Par exemple, 3 % 2 est 1 car le reste de 3 et 2 est 1.

Étant donné que nextLong() génère un pseudo-aléatoire long uniformément distribué dans la plage de [- (2 ^ 48), 2 ^ 48) (ou quelque part dans cette plage), vous devrez en prendre la valeur absolue. Sinon, le modulo de la méthode nextLong() a 50% de chances de renvoyer une valeur négative, ce qui est en dehors de la plage [0, m).

Ce que vous aviez initialement demandé était un pseudo-aléatoire uniformément distribué, long compris dans la gamme de [0,100). Le code suivant le fait:

Math.abs(Rand.nextLong()) % 100;
2
TheGamePlayer 40

De la page sur Random :

La méthode nextLong est implémentée par la classe Random comme si:

public long nextLong() {
   return ((long)next(32) << 32) + next(32);
}

Comme la classe Random utilise une graine de 48 bits seulement, cet algorithme ne renverra pas toutes les valeurs longues possibles.

Donc, si vous voulez obtenir une Long, vous n'allez déjà pas avoir la plage complète de 64 bits.

Je suggérerais que si vous avez une plage proche de la puissance 2, vous construisez la variable Long comme dans l'extrait, comme ceci:

next(32) + ((long)nextInt(8) << 3)

pour obtenir une plage de 35 bits, par exemple.

1
Phil

À partir de l'API Java 8 

Il serait peut-être plus facile d’implémenter l’implémentation réelle dans API dochttps://docs.Oracle.com/javase/8/docs/api/Java/util/Random.html#longs-long-long-long - Ils l’utilisent pour générer des flux longs. Et votre origine peut être "0" comme dans la question.

long nextLong(long Origin, long bound) {
  long r = nextLong();
  long n = bound - Origin, m = n - 1;
  if ((n & m) == 0L)  // power of two
    r = (r & m) + Origin;
  else if (n > 0L) {  // reject over-represented candidates
    for (long u = r >>> 1;            // ensure nonnegative
         u + m - (r = u % n) < 0L;    // rejection check
         u = nextLong() >>> 1) // retry
        ;
    r += Origin;
  }
  else {              // range not representable as long
    while (r < Origin || r >= bound)
      r = nextLong();
  }
  return r;
}
1
Vitaliy

La méthode ci-dessous vous renverra une valeur comprise entre 10000000000 et 9999999999 

long min = 1000000000L
long max = 9999999999L    

public static long getRandomNumber(long min, long max){

    Random random = new Random();         
    return random.nextLong() % (max - min) + max;

}
1
Arpan Saini

Améliorer encore la réponse de kennytm: Une implémentation de sous-classe prenant en compte l'implémentation réelle dans Java 8 serait:

public class MyRandom extends Random {
  public long nextLong(long bound) {
    if (bound <= 0) {
      throw new IllegalArgumentException("bound must be positive");
    }

    long r = nextLong() & Long.MAX_VALUE;
    long m = bound - 1L;
    if ((bound & m) == 0) { // i.e., bound is a power of 2
      r = (bound * r) >> (Long.SIZE - 1);
    } else {
      for (long u = r; u - (r = u % bound) + m < 0L; u = nextLong() & Long.MAX_VALUE);
    }
    return r;
  }
}
1
Enrice

Que dis-tu de ça:

public static long nextLong(@NonNull Random r, long min, long max) {
    if (min > max)
        throw new IllegalArgumentException("min>max");
    if (min == max)
        return min;
    long n = r.nextLong();
    //abs (use instead of Math.abs, which might return min value) :
    n = n == Long.MIN_VALUE ? 0 : n < 0 ? -n : n;
    //limit to range:
    n = n % (max - min);
    return min + n;
}

?

1

Les méthodes utilisant la fonction r.nextDouble() doivent utiliser:

long number = (long) (Rand.nextDouble()*max);


long number = x+(((long)r.nextDouble())*(y-x));
0
James David Low
public static long randomLong(long min, long max)
{
    try
    {
        Random  random  = new Random();
        long    result  = min + (long) (random.nextDouble() * (max - min));
        return  result;
    }
    catch (Throwable t) {t.printStackTrace();}
    return 0L;
}
0
XXX