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.
I might be missing the obvious here but how about creating two random
BigInteger
s, one being the integer part, and the other the fractional? Obviously the range of the "fractional" bigint would be dictated by the precision you want to allow, which you can't get away from pinning down.Update: This can be further simplified to work with just one random bigint. If you want a random number between 0 and n with k decimal precision (where k is a constant), you just generate a random number between 0 and n*10^k and divide it by 10^k.
I made a post about generating a random BigInteger Andy Turner's answer about generating a random BigInteger. I don't use this directly for generating a random BigDecimal. Essentially my concern is to use independent instances of Random to generate each digit in a number. One problem I noticed is that with Random there are only so many values of and particular number that you get in a row. Also the generation tries to maintain something of an even distribution of generated values. My solution depends on something storing an array or collection of Random instances and calling these. I think this is a good way of going about it and I am trying to find out, so am interested if anyone has any pointers or criticism of this approach.