3

対数分布の乱数を生成しようとしています。

ここで、n = 1は半分の時間で発生し、n = 2は4分の1の時間で発生し、n=3は8分の1の時間で発生します。

    int maxN = 5;
    int t = 1 << (maxN); // 2^maxN
    int n = maxN -
            ((int) (Math.log((Math.random() * t))
            / Math.log(2))); // maxN - log2(1..maxN)
    System.out.println("n=" + n);

ほとんどの場合、必要な結果が得られますが、頻繁に、nよりも大きい値が得られますmaxN

なんでそうなの?私の見方では、の最大値Math.random()は1.0です。
したがって、の最大値(Math.random() * t))t;です。
したがって、t = 2 ^ maxNであるため、log2(t)の最大値はmaxNです。

私の論理はどこで軌道に乗ったのですか?

ありがとう

4

3 に答える 3

7

1.0未満の数値の対数は負です。生成される乱数が1.0未満の場合、式((int) (Math.log(Math.random() * t) / Math.log(2)))は負の数であるためmaxN - (the negative number)、maxNを超えます。

次の式は正しい分布を与えるはずです。

n = Math.floor(Math.log((Math.random() * t) + 1)/Math.log(2))

ご了承ください:

0.0 <= Math.random() <= 1.0
0.0 <= Math.random() * t <= t
1.0 <= (Math.random() * t) + 1 <= t + 1.0
0.0 <= Math.log((Math.random() * t) + 1) <= Math.log(t + 1.0)
0.0 <= Math.log((Math.random() * t) + 1)/Math.log(2) <= Math.log(t + 1.0)/Math.log(2)

Since t = 2^maxN,
Math.log(t + 1.0)/Math.log(2) is slightly larger than maxN.

So do a Math.floor and you get the correct result:
0.0 <= Math.floor(Math.log((Math.random() * t) + 1)/Math.log(2)) <= maxN
于 2010-09-19T13:14:44.673 に答える
2

が1未満の場合、対数の規則に従って、Math.random()*tをとると否定的な答えが得られます。これは、 0.69314718055994530941723212145818であるため、Math.log(Math.random()*t)除算すると否定的な答えが得られることを意味します。Math.log(2)これは、負の数を正の数で割ったものです。答えは否定的です。maxN-負の数=maxN+正の数なので、nはmaxNよりも大きくなります。このキャストMath.random()* tをintに修正し、1を追加するには

int n = maxN -
        ((int) (Math.log((int)((Math.random() * t)+1))
        / Math.log(2))); // maxN - log2(1..maxN)

ログ内のキャストと1の追加に注意してください。

1を追加する目的は、0を回避することです。0のログを取ることはできません。また、1を追加しないと、Math.random()が1を生成しないため、ログ内でmaxNを取得することはできません。 1の半分、2、4、3、および8を取得すると、0から始まります。これにより、0、半分、1、4、2、8などが得られます。

于 2010-09-19T13:14:44.567 に答える
1

問題はスケールの反対側にあります。

非常に小さな乱数を取得した場合にどうなるかを考えてください。

于 2010-09-19T13:15:26.930 に答える