3

我正在尝试生成具有对数分布的随机数。

其中 n=1 出现一半时间,n=2 出现四分之一时间,n=3 出现八分之一时间,以此类推。

    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;
因此 log2(t) 的最大值是 maxN,因为 t = 2^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当您取 时,您将得到否定答案。Math.log(Math.random()*t)这意味着当你除以Math.log(2)0.69314718055994530941723212145818 时,你会得到否定的答案。这是一个负数除以一个正数。答案是否定的。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 的加法。

加一的目的是避免 0。不能记录 0。此外,如果不加 1,则永远无法在日志中获得 maxN,因为 Math.random() 永远不会产生 1。这样,相反得到 1 的一半、2、第四、3 和第八,它只是从 0 开始。这给出了 0、一半、1 第四、2 第八等。

于 2010-09-19T13:14:44.567 回答
1

问题出在天平的另一端。

考虑一下如果你得到一个非常的随机数会发生什么。

于 2010-09-19T13:15:26.930 回答