Search code examples
javamathrandombigintegerbigdecimal

How can I create a random BigDecimal in Java?


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;
}

Solution

  • 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.