Pseudo Random Numbers in Specific Range


Pseudo Random Numbers

Java provides, as part of the utils package, a basic pseudo-random number generator, appropriately named Random. This object can be used to generate a pseudo-random value as any of the built-in numerical datatypes (int, float, etc). You can also use it to generate a random Boolean value, or a random array of bytes. An example usage is as follows:

import java.util.Random;
 
public class CustomRandomExample {
    public static void main(String[] args) {
        // Create a Random object
        Random customRandom = new Random();
 
        // Generate random values of different types
        int customRandInt = customRandom.nextInt();
        long customRandLong = customRandom.nextLong();
        double customRandDouble = customRandom.nextDouble(); // Value between 0.0 and 1.0
        float customRandFloat = customRandom.nextFloat(); // Same as nextDouble
 
        // Generate an array of random bytes
        byte[] customRandBytes = new byte[16];
        customRandom.nextBytes(customRandBytes); // Fills the byte array with random bytes
 
        // Display the generated random values
        System.out.println("Random Integer: " + customRandInt);
        System.out.println("Random Long: " + customRandLong);
        System.out.println("Random Double: " + customRandDouble);
        System.out.println("Random Float: " + customRandFloat);
 
        // Display the generated random bytes
        System.out.print("Random Bytes: ");
        for (byte b : customRandBytes) {
            System.out.print(b + " ");
        }
    }
}

NOTE : This class only produces fairly low-quality pseudo-random numbers, and should never be used to generate random numbers for cryptographic operations or other situations where higher-quality randomness is critical (For that, you would want to use the SecureRandom class, as noted below). An explanation for the distinction between "secure" and "insecure" randomness is beyond the scope of this example.


Pseudo Random Numbers in Specific Range

The method nextInt(int bound) of Random accepts an upper exclusive boundary, i.e. a number that the returned random value must be less than. However, only the nextInt method accepts a bound; nextLong, nextDouble etc. do not

Random random = new Random();
random.nextInt(1000); // 0 - 999
 
int number = 10 + random.nextInt(100); // number is in the range of 10 to 109

Starting in Java 1.7, you may also use ThreadLocalRandom (source). This class provides a thread-safe PRNG (pseudo-random number generator). Note that the nextInt method of this class accepts both an upper and lower bound.

import java.util.concurrent.ThreadLocalRandom;
 
// nextInt is normally exclusive of the top value,
// so add 1 to make it inclusive
ThreadLocalRandom.current().nextInt(min, max + 1);

Note that the official documentation states that nextInt(int bound) can do weird things when bound is near 230+1 (emphasis added):

  • The algorithm is slightly tricky. It rejects values that would result in an uneven distribution (due to the fact that 2^31 is not divisible by n). The probability of a value being rejected depends on n. The worst
  • case is n=2^30+1, for which the probability of a reject is 1/2, and the expected number of iterations before the loop terminates is 2.

In other words, specifying a bound will (slightly) decrease the performance of the nextInt method, and this performance decrease will become more pronounced as the bound approaches half the max int value.


Generating cryptographically secure pseudorandom numbers

Random and ThreadLocalRandom are good enough for everyday use, but they have a big problem: They are based on a linear congruential generator, an algorithm whose output can be predicted rather easily. Thus, these two classes are not suitable for cryptographic uses (such as key generation).

One can use java.security.SecureRandom in situations where a PRNG with an output that is very hard to predict is required. Predicting the random numbers created by instances of this class is hard enough to label the class as cryptographically secure

import java.security.SecureRandom;
import java.util.Arrays;
public class Foo {
	public static void main(String[] args) {
		SecureRandom rng = new SecureRandom();
		byte[] randomBytes = new byte[64];
		rng.nextBytes(randomBytes); // Fills randomBytes with random bytes (duh)
		System.out.println(Arrays.toString(randomBytes));
	}
}

Besides being cryptographically secure, SecureRandom has a gigantic period of 2160, compared to Randoms period of 248. It has one drawback of being considerably slower than Random and other linear PRNGs such as Mersenne Twister and Xorshift, however.

Note that SecureRandom implementation is both platform and provider dependent. The default SecureRandom (given by SUN provider in sun.security.provider.SecureRandom):

  • on Unix-like systems, seeded with data from /dev/random and/or /dev/urandom.
  • on Windows, seeded with calls to CryptGenRandom() in CryptoAPI.

Basic Programs