This question: How to generate a random BigInteger describes a way to achieve the same semantics as Random.nextInt(int n) for BigIntegers.
I would like to do the same for BigDecimal and Random.nextDouble().
One answer in the above question suggests creating a random BigInteger and then creating a BigDouble from it with a random scale. A very quick experiment shows this to be a very bad idea :)
My intuition is that using this method would require the integer to be scaled by something like n-log10(R)
, where n is the number of digits of precision required in the output and R is the random BigInteger. This should allow the correct number of digits to be present so that (for example) 1 -> 10^-64 and 10^64 -> 1.
The scaling value also needs to be chosen correctly for the result to fall in the range [0,1].
Has anyone done this before, and do they know if the results are correctly distributed? Is there a better way to achieve this?
EDIT: Thanks to @biziclop for correcting my understanding of the scale argument. The above isn't necessary, a constant scale factor has the desired effect.
For later reference, my (apparently working code) is:
private static BigDecimal newRandomBigDecimal(Random r, int precision) {
BigInteger n = BigInteger.TEN.pow(precision);
return new BigDecimal(newRandomBigInteger(n, r), precision);
}
private static BigInteger newRandomBigInteger(BigInteger n, Random rnd) {
BigInteger r;
do {
r = new BigInteger(n.bitLength(), rnd);
} while (r.compareTo(n) >= 0);
return r;
}
It's surely very easy... if I only knew what you want. For a uniformly distributed number in range [0, 1) and precision N decimal digits generate a uniform BigInteger less than 10*N and scale it down by 10*N.