Подтвердить что ты не робот

Java: случайное длинное число в диапазоне 0 <= x <n

Случайный класс имеет метод генерации случайного int в заданном диапазоне. Например:

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

Это приведет к тому, что число int больше или равно 0 и меньше 100. Я бы хотел сделать то же самое с длинным числом.

long y = magicRandomLongGenerator(100);

Случайный класс имеет только nextLong(), но он не позволяет устанавливать диапазон.

4b9b3361

Ответ 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 и позволяет вам выбирать семя, если вы хотите воспроизводимую последовательность чисел.

Ответ 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