Java: random long number in 0 <= x < n range

2019-01-05 00:01发布

Random class has a method to generate random int in a given range. For example:

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

This would generate an int number more or equal to 0 and less than 100. I'd like to do exactly the same with long number.

long y = magicRandomLongGenerator(100);

Random class has only nextLong(), but it doesn't allow to set range.

15条回答
We Are One
2楼-- · 2019-01-05 00:19

From the page on Random:

The method nextLong is implemented by class Random as if by:

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

Because class Random uses a seed with only 48 bits, this algorithm will not return all possible long values.

So if you want to get a Long, you're already not going to get the full 64 bit range.

I would suggest that if you have a range that falls near a power of 2, you build up the Long as in that snippet, like this:

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

to get a 35 bit range, for example.

查看更多
\"骚年 ilove
3楼-- · 2019-01-05 00:20

//use system time as seed value to get a good random number

   Random random = new Random(System.currentTimeMillis());
              long x;
             do{
                x=random.nextLong();
             }while(x<0 && x > n); 

//Loop until get a number greater or equal to 0 and smaller than n

查看更多
戒情不戒烟
4楼-- · 2019-01-05 00:26

The methods using the r.nextDouble() should use:

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


long number = x+(((long)r.nextDouble())*(y-x));
查看更多
We Are One
5楼-- · 2019-01-05 00:27

Starting from Java 7 (or Android API Level 21 = 5.0+) you could directly use ThreadLocalRandom.current().nextLong(n) (for 0 ≤ x < n) and ThreadLocalRandom.current().nextLong(m, n) (for m ≤ x < n). See @Alex's answer for detail.


If you are stuck with Java 6 (or Android 4.x) you need to use an external library (e.g. org.apache.commons.math3.random.RandomDataGenerator.getRandomGenerator().nextLong(0, n-1), see @mawaldne's answer), or implement your own nextLong(n).

According to http://java.sun.com/j2se/1.5.0/docs/api/java/util/Random.html nextInt is implemented as

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

So we may modify this to perform 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;
}
查看更多
小情绪 Triste *
6楼-- · 2019-01-05 00:27

Further improving kennytm's answer: A subclass implementation taking the actual implementation in Java 8 into account would be:

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楼-- · 2019-01-05 00:28

From Java 8 API

It could be easier to take actual implementation from API doc https://docs.oracle.com/javase/8/docs/api/java/util/Random.html#longs-long-long-long- they are using it to generate longs stream. And your origin can be "0" like in the 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;
}
查看更多
登录 后发表回答