Generate 8-byte number in Java

Asked by At

I'm a little bit confused, how to do this. I know I can use Random class to generate random numbers, but I don't know how to specify and generate 8-byte number?

Thanks, Vuk

5 Answers

13
aioobe On Best Solutions

You should note that the java.util.Random class uses a 48-bit seed, so not all 8-byte values (sequences of 64 bits) can be generated using this class. Due to this restriction I suggest you use SecureRandom and the nextBytes method in this situation.

The usage is quite similar to the java.util.Random solution.

SecureRandom sr = new SecureRandom();
byte[] rndBytes = new byte[8];
sr.nextBytes(rndBytes);

Here is the reason why a 48-bit seed is not enough:

  • The Random class implements a pseudo random generator which means that it is deterministic.
  • The current "state" of the Random determines the future sequence of bits.
  • Since it has 248 states, it can't have more than 248 possible future sequences.
  • Since an 8-byte value has 264 different possibilities, some of these possibilities will never be read from the Random object.

Based on @Peter Lawreys excellent answer (it deserves more upvotes!): Here is a solution for creating a java.util.Random with 2×48-bit seed. That is, a java.util.Random instance capable of generating all possible longs.

class Random96 extends Random {
    int count = 0;
    ExposedRandom extra48bits;

    class ExposedRandom extends Random {
        public int next(int bits) {    // Expose the next-method.
            return super.next(bits);
        }
    }

    @Override
    protected int next(int bits) {
        if (count++ == 0)
            extra48bits = new ExposedRandom();
        return super.next(bits) ^ extra48bits.next(bits) << 1;
    }
}
5
Roman On

It can be done either with byte array of length 8:

byte[] byteArray = new byte[8];    
random.nextBytes(byteArray);

or with a variable of type long (which represents 8-byte numbers):

long randomLong = random.nextLong();
0
Mateen Ulhaq On

A little adjusting from the code here:

import java.util.Random;

/** Generate 10 random integers in the range 0..99. */
public final class RandomByte {

  public static final void main(String... aArgs){
    log("Generating 10 random integers in range 0..255.");

    //note a single Random object is reused here
    Random randomGenerator = new Random();
    for (int idx = 1; idx <= 10; ++idx){
      int randomInt = randomGenerator.nextInt(256);
      // int randomInt = randomGenerator.nextBytes(256);
      log("Generated : " + randomInt);
    }

    log("Done.");
  }

  private static void log(String aMessage){
    System.out.println(aMessage);
  }
}

Some further reading: Math.random() versus Random.nextInt(int)

2
Michael Borgwardt On

The long type is an 8 byte signed integer, so Random.nextLong() seems to do what you want. Or if you need a byte array as result:

byte[] result = new byte[8];
Random.nextBytes(result);
12
Peter Lawrey On

I agree with @aioobe' point about Random using a 48-bit seed. SecureRandom is a better solution. However to answer the OP's questions of how to use the Random class and still allow for all possible 8-byte values is to reset the seed periodically.

int counter = 0;
Random rand = new Random();
Random rand2 = new Random();

if (++counter == 0) rand = new Random(); // reset every 4 billion values.

long randomLong = rand.nextLong() ^ rand2.nextLong() << 1;

Random only allows a sequence of 2^47 long values. By using two Random generators, one which keeps jumping around in the sequence, you get two 2^47 * 2^47 possible values. The use of << 1 is to avoid the impact of having both randoms having the same seed (in which case ^ would produce 0 for 4 billion values in a row)