6

この質問:ランダムなBigIntegerを生成する方法は、BigIntegerのRandom.nextInt(int n)と同じセマンティクスを実現する方法を説明しています。

BigDecimalとRandom.nextDouble()についても同じことをしたいと思います。

上記の質問の1つの答えは、ランダムなBigIntegerを作成し、それからランダムなスケールでBigDoubleを作成することを提案しています。非常に簡単な実験は、これが非常に悪い考えであることを示しています:)

私の直感では、このメソッドを使用するには、整数をのようなものでスケーリングする必要がありますn-log10(R)。ここで、nは出力に必要な精度の桁数であり、RはランダムなBigIntegerです。これにより、(たとえば)1-> 10^-64および10^64-> 1となるように、正しい桁数が存在するようになります。

結果が[0,1]の範囲に収まるようにするには、スケーリング値も正しく選択する必要があります。

誰かが以前にこれを行ったことがあり、結果が正しく配布されているかどうかを知っていますか?これを達成するためのより良い方法はありますか?

編集:スケール引数の私の理解を修正してくれた@biziclopに感謝します。上記は必須ではありません。一定の倍率で目的の効果が得られます。

後で参照するために、私の(明らかに機能しているコード)は次のとおりです。

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

3 に答える 3

3

それは確かに非常に簡単です... 私があなたが何を望んでいるのかを知っていれば. [0, 1) の範囲で一様に分布した数と精度 N 桁の場合、10* N 未満の一様な BigInteger を生成し、それを 10 *N だけ縮小します。

于 2011-02-04T16:34:06.353 に答える
2

ランダムな BigInteger の生成に関する投稿を作成しました ランダムな BigIntegerの生成に関する Andy Turner の回答。ランダムな BigDecimal を生成するためにこれを直接使用することはありません。基本的に私の関心事は、Random の独立したインスタンスを使用して、数値の各桁を生成することです。私が気付いた 1 つの問題は、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;
}
于 2011-02-17T11:05:17.213 に答える
1

BigIntegerここで明らかなことを見逃しているかもしれませんが、1 つが整数部分で、もう 1 つが小数部分である2 つの random を作成するのはどうですか? 明らかに、「小数」のbigintの範囲は、許可したい精度によって決まります。これは、ピン留めから逃れることはできません。

更新: これはさらに単純化して、ランダムな bigint を 1 つだけ使用することができます。0 から n の間の 10 進精度 k (k は定数) の乱数が必要な場合は、0 から n*10^k の間の乱数を生成し、それを 10^k で割ります。

于 2011-02-04T16:22:03.667 に答える