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?
Compile this F# code into a DLL and you can also reference it in your C# / VB.NET programs
Use a loop:
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:
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 therandomSource
instance is exceptionally slow.The following method uses the
BigInteger(int numBits, Random rnd)
constructor and rejects the result if it's bigger than the specified n.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.
Here is how I do it in a class called Generic_BigInteger available via: Andy Turner's Generic Source Code Web Page
The simplest approach (by quite a long way) would be to use the specified constructor to generate a random number with the right number of bits (
floor(log2 n) + 1
), and then throw it away if it's greater than n. In the worst possible case (e.g. a number in the range [0, 2n + 1) you'll throw away just under half the values you create, on average.Why not constructing a random BigInteger, then building a BigDecimal from it ? There is a constructor in BigDecimal :
public BigDecimal(BigInteger unscaledVal, int scale)
that seems relevant here, no ? Give it a random BigInteger and a random scale int, and you'll have a random BigDecimal. No ?