How to create random BigDecimal in Java?

This question: How to create 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 involves creating a random BigInteger and then creating a BigDouble from it with a random scale. A very quick experiment shows that this is a very bad idea :)

My intuition is that using this method requires an integer to scale something like n-log10(R), where n is the number of precision digits needed for output, and R is a 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 must also be correctly selected so that the result falls into the range [0,1].

Has anyone done this before and they know if the results are distributed correctly? Is there a better way to achieve this?

EDIT: Thanks to @biziclop for correcting my understanding of the scale argument. The foregoing is not required; a constant scale factor has the desired effect.

For later reference, my (apparently working code):

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;
}
+5
3

, ... , . [0, 1) N BigInteger 10 * N 10 * N.

+3

BigInteger BigInteger. BigDecimal. , Random . , , , Random , . - . , . , , , , - .

/**
 *
 * @param a_Random
 * @param decimalPlaces
 * @param lowerLimit
 * @param upperLimit
 * @return a pseudo randomly constructed BigDecimal in the range from
 * lowerLimit to upperLimit inclusive and that has up to decimalPlaces
 * number of decimal places
 */
public static BigDecimal getRandom(
        Generic_Number a_Generic_Number,
        int decimalPlaces,
        BigDecimal lowerLimit,
        BigDecimal upperLimit) {
    BigDecimal result;
    BigDecimal range = upperLimit.subtract(lowerLimit);
    BigDecimal[] rangeDivideAndRemainder =
            range.divideAndRemainder(BigDecimal.ONE);
    BigInteger rangeInt = rangeDivideAndRemainder[0].toBigIntegerExact();
    BigInteger intComponent_BigInteger = Generic_BigInteger.getRandom(
            a_Generic_Number,
            rangeInt);
    BigDecimal intComponent_BigDecimal =
            new BigDecimal(intComponent_BigInteger);
    BigDecimal fractionalComponent;
    if (intComponent_BigInteger.compareTo(rangeInt) == 0) {
        BigInteger rangeRemainder =
                rangeDivideAndRemainder[1].toBigIntegerExact();
        BigInteger fractionalComponent_BigInteger =
                Generic_BigInteger.getRandom(a_Generic_Number, rangeRemainder);
        String fractionalComponent_String = "0.";
        fractionalComponent_String += fractionalComponent_BigInteger.toString();
        fractionalComponent = new BigDecimal(fractionalComponent_String);
    } else {
        fractionalComponent = getRandom(
                a_Generic_Number, decimalPlaces);
    }
    result = intComponent_BigDecimal.add(fractionalComponent);
    result.add(lowerLimit);
    return result;
}

/**
 * Provided for convenience.
 * @param a_Generic_BigDecimal
 * @param decimalPlaces
 * @return a random BigDecimal between 0 and 1 inclusive which can have up
 * to decimalPlaces number of decimal places
 */
public static BigDecimal getRandom(
        Generic_Number a_Generic_Number,
        int decimalPlaces) {
    //Generic_BigDecimal a_Generic_BigDecimal = new Generic_BigDecimal();
    Random[] random = a_Generic_Number.get_RandomArrayMinLength(
            decimalPlaces);
    //System.out.println("Got Random[] size " + random.length);
    String value = "0.";
    int digit;
    int ten_int = 10;
    for (int i = 0; i < decimalPlaces; i++) {
        digit = random[i].nextInt(ten_int);
        value += digit;
    }
    int length = value.length();
    // Tidy values ending with zero's
    while (value.endsWith("0")) {
        length--;
        value = value.substring(0, length);
    }
    if (value.endsWith(".")) {
        value = "0";
    }
    BigDecimal result = new BigDecimal(value);
    //result.stripTrailingZeros();
    return result;
}
+2

, BigInteger s, , - ? , "" bigint , , .

: bigint. 0 n k ( k - ), 0 n * 10 ^ k 10 ^ k.

+1

All Articles