Vilius Normantas
Vilius Normantas

Reputation: 3758

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

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.

Upvotes: 162

Views: 200950

Answers (18)

arthurthecat
arthurthecat

Reputation: 1

Came across this post when looking at using    new Random(3142L).longNext()

Looked at    java    jdk1.8.0_381 src where the line "...

  • Because class {@code Random} uses a seed with only 48 bits, this algorithm will not return all possible {@code long} values. ..."

from

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

concerned me but when I looked at src for    Random(seed)    and    .nextLong()

I came to think that though    protected int next(bits)    takes integer from Long only 48 bits of which is random bits, integer returned covers all value of an integer    ie 0x0000->0xFFFF   

Long returned by    .nextLong()    is constructed from two separate integers from    .next()    One placed as most significant int of Long and one placed as least significant int

As each int covers all values of integer I think all values of Long will be covered, though. So    .nextLong()    is adequate for returning all values of Long and better than Random documentation suggests.

As to your problem, Long has no advantages over int when working with numbers from 0-100.    Casting    .nextInt(100)    to Long is probably the best solution

long[] aol=new long[0];
Random r=new Random();
long next(){  return (long)( r.nextInt(100) );  }
for(int i=0; i<100; i++){  aol[i++]=this.next();  }

Yields random array of 100 Long values

Upvotes: 0

kennytm
kennytm

Reputation: 523344

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 Random documentation, nextInt is implemented as

 public int nextInt(int bound) {
   if (bound <= 0)
     throw new IllegalArgumentException("bound must be positive");

   if ((bound & -bound) == bound)  // i.e., bound is a power of 2
     return (int)((bound * (long)next(31)) >> 31);

   int bits, val;
   do {
       bits = next(31);
       val = bits % bound;
   } while (bits - val + (bound-1) < 0);
   return val;
 }

So we may modify this to perform nextLong:

long nextLong(Random rng, long bound) {
    // error checking and 2^x checking removed for simplicity.
    long bits, val;
    do {
        bits = (rng.nextLong() << 1) >>> 1;
        val = bits % bound;
    } while (bits-val+(bound-1) < 0L);
    return val;
}

Upvotes: 186

TheGamePlayer 40
TheGamePlayer 40

Reputation: 67

WARNING

Note that System.out.println(Math.abs(Integer.MIN_VALUE)); prints -2147483648, meaning that if rand.nextLong() picks Integer.MIN_VALUE, a negative value is returned. This is misleading because Math.abs() does not return a positive number in all cases.


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;

Upvotes: 4

PKS
PKS

Reputation: 763

public static Long generate(int length) {
    StringBuilder sb = new StringBuilder("1");
    sb.setLength(length + 1);
    String padded = sb.toString().replaceAll("[^0-9]", "0");
    long rand = 0;
    try {
      rand = (long) (Math.random()*Long.valueOf(padded));
    } catch (Exception e) {
    }
    return rand;
  }

Upvotes: 0

Liash101
Liash101

Reputation: 11

import java.util*;

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

This should work

Upvotes: 0

Sridhar Sg
Sridhar Sg

Reputation: 1596

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.

Upvotes: 0

Vitaliy
Vitaliy

Reputation: 426

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

Upvotes: 2

Arpan Saini
Arpan Saini

Reputation: 5191

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;

}

Upvotes: 2

Alex - GlassEditor.com
Alex - GlassEditor.com

Reputation: 15507

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.

Upvotes: 113

XXX
XXX

Reputation: 9072

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

Upvotes: -1

android developer
android developer

Reputation: 116412

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

?

Upvotes: 2

Enrice
Enrice

Reputation: 53

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

Upvotes: 3

Valentinos Ioannou
Valentinos Ioannou

Reputation: 31

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

Upvotes: -5

Septic Overflow
Septic Overflow

Reputation: 135

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

Upvotes: 11

mawaldne
mawaldne

Reputation: 3998

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)

Upvotes: 12

M. Jessup
M. Jessup

Reputation: 8222

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.

Upvotes: 75

J Low
J Low

Reputation: 79

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

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


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

Upvotes: 0

Phil
Phil

Reputation: 2927

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.

Upvotes: 1

Related Questions