views:

577

answers:

3

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.

+1  A: 

The standard method to generate a number (without a utility method) in a range is to just use the double with the range:

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

will give you a long between 0 (inclusive) and range (exclusive). Similarly if you want a number between x and y:

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

will give you a long from 1234567 (inclusive) through 123456789 (exclusive)

M. Jessup
My first idea was exactly this. But it seems to be a bit inelegant. And I'm worried about uniformness of the distribution (it's not that I really need it, I just want to do it right)
Vilius Normantas
+4  A: 

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;
}
KennyTM
I'm having some problems with "2^x checking" part. Any ideas?
Vilius Normantas
@Vilius: The 2^x checking just makes the generation faster because directly using `rng.nextLong() % n` will be give uniform values (assume all bits are good). You can ignore that part if you want.
KennyTM
This worked. Thank you guys :)
Vilius Normantas
+1  A: 

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.

Phil
But the documentation says "All 2^64 possible long values are produced with (approximately) equal probability."So apparently the nextLong() method should return all possible values.. Btw, how length of the seed is related to distribution of values?
Vilius Normantas