Java: случайное длинное число в диапазоне 0 <= x <n
Случайный класс имеет метод генерации случайного int в заданном диапазоне. Например:
Random r = new Random();
int x = r.nextInt(100);
Это приведет к тому, что число int больше или равно 0 и меньше 100. Я бы хотел сделать то же самое с длинным числом.
long y = magicRandomLongGenerator(100);
Случайный класс имеет только nextLong(), но он не позволяет устанавливать диапазон.
Ответы
Ответ 1
Начиная с Java 7 (или Android API уровня 21 = 5.0+) вы можете напрямую использовать ThreadLocalRandom.current().nextLong(n)
(для 0 ≤ x < n) и ThreadLocalRandom.current().nextLong(m, n)
(для m ≤ x < n). Подробнее см. @Alex.
Если вы застряли в Java 6 (или Android 4.x), вам нужно использовать внешнюю библиотеку (например, org.apache.commons.math3.random.RandomDataGenerator.getRandomGenerator().nextLong(0, n-1)
, см. @mawaldne) или реализовать свой собственный nextLong(n)
.
Согласно http://java.sun.com/j2se/1.5.0/docs/api/java/util/Random.html nextInt
реализуется как
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;
}
Итак, мы можем изменить это, чтобы выполнить 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;
}
Ответ 2
Стандартный метод генерации числа (без метода утилиты) в диапазоне состоит в том, чтобы просто использовать double с диапазоном:
long range = 1234567L;
Random r = new Random()
long number = (long)(r.nextDouble()*range);
даст вам длинный промежуток между 0 (включительно) и диапазоном (эксклюзивный). Аналогично, если вам нужно число между x и y:
long x = 1234567L;
long y = 23456789L;
Random r = new Random()
long number = x+((long)(r.nextDouble()*(y-x)));
даст вам длинный от 1234567 (включительно) до 123456789 (эксклюзивный)
Примечание: установите круглые скобки, потому что отбрасывание в long имеет более высокий приоритет, чем умножение.
Ответ 3
ThreadLocalRandom
ThreadLocalRandom
имеет метод nextLong(long bound)
.
long v = ThreadLocalRandom.current().nextLong(100);
Он также имеет nextLong(long origin, long bound)
, если вам требуется источник, отличный от 0. Передайте начало (включительно) и связанное (исключая).
long v = ThreadLocalRandom.current().nextLong(10,100); // For 2-digit integers, 10-99 inclusive.
SplittableRandom
имеет те же методы nextLong
и позволяет вам выбирать семя, если вы хотите воспроизводимую последовательность чисел.
Ответ 4
Методы выше отлично работают. Если вы используете apache commons (org.apache.commons.math.random), просмотрите RandomData. У него есть метод: nextLong (длинный нижний, длинный верхний)
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)
Ответ 5
Используйте оператор "%"
resultingNumber = (r.nextLong() % (maximum - minimum)) + minimum;
Используя оператор "%", мы берем остаток при делении на ваше максимальное значение. Это оставляет нам только числа от 0 (включительно) до делителя (исключая).
Например:
public long randLong(long min, long max) {
return (new java.util.Random().nextLong() % (max - min)) + min;
}
Ответ 6
Дальнейшее улучшение ответа на kennytm: реализация подкласса, учитывающая фактическую реализацию на Java 8, будет:
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;
}
}
Ответ 7
Большое вам спасибо за этот пост. Это то, что мне нужно. Пришлось что-то изменить, чтобы получить часть, с которой я работал.
Я получил следующее (включено выше):
long number = x+((long)r.nextDouble()*(y-x));
изменив его на:
long number = x+ (long)(r.nextDouble()*(y-x));
так как (long)r.nextDouble()
всегда равно нулю.
Ответ 8
Если вы хотите, чтобы равномерно распределенная псевдослучайность длилась в диапазоне от [0, m
), попробуйте использовать оператор modulo и метод абсолютного значения в сочетании с методом nextLong()
, как показано ниже:
Math.abs(rand.nextLong()) % m;
Где rand
- ваш случайный объект.
Оператор modulo делит два числа и выводит оставшуюся часть этих чисел. Например, 3 % 2
- 1
, потому что остаток от 3 и 2 равен 1.
Так как nextLong()
порождает равномерно распределенное псевдослучайное длинное число в диапазоне [- (2 ^ 48), 2 ^ 48) (или где-то в этом диапазоне), вам нужно будет принять его абсолютное значение. Если вы этого не сделаете, то по модулю метода nextLong()
есть 50% -ный шанс вернуть отрицательное значение, которое находится вне диапазона [0, m
).
То, что вы изначально запросили, было равномерно распределенным псевдослучайным долго в диапазоне [0,100). Следующий код делает это:
Math.abs(rand.nextLong()) % 100;
Ответ 9
Из Java 8 API
Может быть проще взять фактическую реализацию из API doc https://docs.oracle.com/javase/8/docs/api/java/util/Random.html#longs-long-long-long-
онииспользуют его для генерации длинного потока. И ваше происхождение может быть "0", как в вопросе.
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;
}
Ответ 10
На странице Random:
Метод nextLong реализуется классом Random, как если бы:
public long nextLong() {
return ((long)next(32) << 32) + next(32);
}
Поскольку класс Random использует семя только с 48 бит, этот алгоритм не будет возвращать все возможные длинные значения.
Итак, если вы хотите получить Long
, вы уже не получите полный 64-разрядный диапазон.
Я бы предположил, что если у вас есть диапазон, который падает рядом с мощностью 2, вы создаете Long
как в этом фрагменте, например:
next(32) + ((long)nextInt(8) << 3)
чтобы получить, например, 35-битный диапазон.
Ответ 11
Как насчет этого:
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;
}
?
Ответ 12
Приведенный ниже метод вернет вам значение от 10000000000 до 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;
}
Ответ 13
Методы, использующие r.nextDouble()
, должны использовать:
long number = (long) (rand.nextDouble()*max);
long number = x+(((long)r.nextDouble())*(y-x));
Ответ 14
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;
}
Ответ 15
Если вы можете использовать потоки Java, попробуйте следующее:
Random randomizeTimestamp = new Random();
Long min = ZonedDateTime.parse("2018-01-01T00:00:00.000Z").toInstant().toEpochMilli();
Long max = ZonedDateTime.parse("2019-01-01T00:00:00.000Z").toInstant().toEpochMilli();
randomizeTimestamp.longs(generatedEventListSize, min, max).forEach(timestamp -> {
System.out.println(timestamp);
});
Это будет генерировать числа в заданном диапазоне для длинных.
Ответ 16
//использовать системное время в качестве начального значения для получения хорошего случайного числа
Random random = new Random(System.currentTimeMillis());
long x;
do{
x=random.nextLong();
}while(x<0 && x > n);
//Петля, пока не получится число больше или равно 0 и меньше n