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

JavaRandomRangeLong Integer

Java Problem Overview


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.

Java Solutions


Solution 1 - Java

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 <https://docs.oracle.com/javase/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;
}

Solution 2 - Java

ThreadLocalRandom

ThreadLocalRandom has a nextLong(long bound) method.

long v = ThreadLocalRandom.current().nextLong(100);

It also has nextLong(long origin, long bound) if you need an origin other than 0. Pass the origin (inclusive) and the bound (exclusive).

long v = ThreadLocalRandom.current().nextLong(10,100); // For 2-digit integers, 10-99 inclusive.

SplittableRandom has the same nextLong methods and allows you to choose a seed if you want a reproducible sequence of numbers.

Solution 3 - Java

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)

Note: check parentheses, because casting to long has higher priority than multiplication.

Solution 4 - Java

The methods above work great. If you're using apache commons (org.apache.commons.math.random) check out RandomData. It has a method: nextLong(long lower, long upper)

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)

Solution 5 - Java

Use the '%' operator

resultingNumber = (r.nextLong() % (maximum - minimum)) + minimum;

By using the '%' operator, we take the remainder when divided by your maximum value. This leaves us with only numbers from 0 (inclusive) to the divisor (exclusive).

For example:

public long randLong(long min, long max) {
    return (new java.util.Random().nextLong() % (max - min)) + min;
}

Solution 6 - Java

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

Solution 7 - Java

If you want a uniformly distributed pseudorandom long in the range of [0,m), try using the modulo operator and the absolute value method combined with the nextLong() method as seen below:

Math.abs(rand.nextLong()) % m;

Where rand is your Random object.

The modulo operator divides two numbers and outputs the remainder of those numbers. For example, 3 % 2 is 1 because the remainder of 3 and 2 is 1.

Since nextLong() generates a uniformly distributed pseudorandom long in the range of [-(2^48),2^48) (or somewhere in that range), you will need to take the absolute value of it. If you don't, the modulo of the nextLong() method has a 50% chance of returning a negative value, which is out of the range [0,m).

What you initially requested was a uniformly distributed pseudorandom long in the range of [0,100). The following code does so:

Math.abs(rand.nextLong()) % 100;

Solution 8 - Java

How about this:

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

?

Solution 9 - Java

The below Method will Return you a value between 10000000000 to 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;
        	    
}
    

Solution 10 - Java

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

Solution 11 - Java

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.

Solution 12 - Java

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

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


long number = x+(((long)r.nextDouble())*(y-x));

Solution 13 - Java

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

Solution 14 - Java

If you can use java streams, you can try the following:

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

This will generate numbers in the given range for longs.

Solution 15 - Java

import java.util*;

    Random rnd = new Random ();
    long name = Math.abs(rnd.nextLong());
   

This should work

Solution 16 - Java

//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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionVilius NormantasView Question on Stackoverflow
Solution 1 - JavakennytmView Answer on Stackoverflow
Solution 2 - JavaAlex - GlassEditor.comView Answer on Stackoverflow
Solution 3 - JavaM. JessupView Answer on Stackoverflow
Solution 4 - JavamawaldneView Answer on Stackoverflow
Solution 5 - JavaSeptic OverflowView Answer on Stackoverflow
Solution 6 - JavaEnriceView Answer on Stackoverflow
Solution 7 - JavaTheGamePlayer 40View Answer on Stackoverflow
Solution 8 - Javaandroid developerView Answer on Stackoverflow
Solution 9 - JavaArpan SainiView Answer on Stackoverflow
Solution 10 - JavaVitaliyView Answer on Stackoverflow
Solution 11 - JavaPhilView Answer on Stackoverflow
Solution 12 - JavaJ LowView Answer on Stackoverflow
Solution 13 - JavaXXXView Answer on Stackoverflow
Solution 14 - JavaSridhar SgView Answer on Stackoverflow
Solution 15 - JavaLiash101View Answer on Stackoverflow
Solution 16 - JavaValentinos IoannouView Answer on Stackoverflow