Java:生成具有对数分布的随机数

时间:2010-09-19 12:58:29

标签: java math random distribution logarithm

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

其中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;

我的逻辑在哪里偏离轨道?

由于

3 个答案:

答案 0 :(得分:6)

小于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

答案 1 :(得分:2)

如果Math.random()*t小于1,那么当你按照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,第四,第三和第八,它只是从0开始。这给了0,一半,一个四分之一,两个八分之一,等等。

答案 2 :(得分:1)

问题出现在规模的另一端。

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