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.
À 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;
}
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.
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.
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)
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;
}
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.
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;
Où 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;
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.
À 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;
}
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;
}
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;
}
}
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;
}
?
Les méthodes utilisant la fonction r.nextDouble()
doivent utiliser:
long number = (long) (Rand.nextDouble()*max);
long number = x+(((long)r.nextDouble())*(y-x));
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;
}