Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to generate a random BigInteger value in Java?

I need to generate arbitrarily large random integers in the range 0 (inclusive) to n (exclusive). My initial thought was to call nextDouble and multiply by n, but once n gets to be larger than 253, the results would no longer be uniformly distributed.

BigInteger has the following constructor available:

public BigInteger(int numBits, Random rnd) 

Constructs a randomly generated BigInteger, uniformly distributed over the range 0 to (2numBits - 1), inclusive.

How can this be used to get a random value in the range 0 - n, where n is not a power of 2?

like image 437
Bill the Lizard Avatar asked Feb 18 '10 16:02

Bill the Lizard


People also ask

How do I get BigInteger value?

BigInteger valueOf() Method in Java we can call this function by BigInteger. valueOf(long value) code. Parameter: This method accepts a single parameter value which is the value of the BigInteger to be created. Return Value: This method returns the BigInteger whose value is equal to value of long passed as parameter.

How do you generate a random number between 10 and Java?

For example, to generate a random number between 1 and 10, we can do it like below. ThreadLocalRandom random = ThreadLocalRandom. current(); int rand = random. nextInt(1, 11);

How do I return BigInteger in Java?

and(BigInteger val) method returns a BigInteger whose value is bitwise-AND of two BigIntegers. This method returns a negative number if both of the BigIntegers are negative. The and() method applies bitwise-AND operation upon the current bigInteger and bigInteger passed as parameter.


2 Answers

Use a loop:

BigInteger randomNumber; do {     randomNumber = new BigInteger(upperLimit.bitLength(), randomSource); } while (randomNumber.compareTo(upperLimit) >= 0); 

on average, this will require less than two iterations, and the selection will be uniform.

Edit: If your RNG is expensive, you can limit the number of iterations the following way:

int nlen = upperLimit.bitLength(); BigInteger nm1 = upperLimit.subtract(BigInteger.ONE); BigInteger randomNumber, temp; do {     temp = new BigInteger(nlen + 100, randomSource);     randomNumber = temp.mod(upperLimit); } while (s.subtract(randomNumber).add(nm1).bitLength() >= nlen + 100); // result is in 'randomNumber' 

With this version, it is highly improbable that the loop is taken more than once (less than one chance in 2^100, i.e. much less than the probability that the host machine spontaneously catches fire in the next following second). On the other hand, the mod() operation is computationally expensive, so this version is probably slower than the previous, unless the randomSource instance is exceptionally slow.

like image 91
Thomas Pornin Avatar answered Sep 20 '22 13:09

Thomas Pornin


The following method uses the BigInteger(int numBits, Random rnd) constructor and rejects the result if it's bigger than the specified n.

public BigInteger nextRandomBigInteger(BigInteger n) {     Random rand = new Random();     BigInteger result = new BigInteger(n.bitLength(), rand);     while( result.compareTo(n) >= 0 ) {         result = new BigInteger(n.bitLength(), rand);     }     return result; } 

The drawback to this is that the constructor is called an unspecified number of times, but in the worst case (n is just slightly greater than a power of 2) the expected number of calls to the constructor should be only about 2 times.

like image 33
Bill the Lizard Avatar answered Sep 21 '22 13:09

Bill the Lizard