代码之家  ›  专栏  ›  技术社区  ›  bguiz

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

  •  3
  • bguiz  · 技术社区  · 15 年前

    我正试图生成一个具有对数分布的随机数。

    其中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 回复  |  直到 12 年前
        1
  •  6
  •   Abhinav Sarkar    15 年前

    小于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
    
        2
  •  2
  •   Leo Izen    15 年前

    如果 Math.random()*t 如果小于1,那么当你选择 Math.log(Math.random()*t) ,按对数规则。这意味着当你除以 Math.log(2) 因为这是0.69314718055994530941723212145818。这是一个负数除以一个正数。答案是否定的。maxn-一个负数=maxn+某个正数,所以n大于maxn。要将此cast 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。这样,它就从0开始,而不是从1/2、1/4、3和8开始。这给0,半,1,四分之一,2,八分之一,等等。

        3
  •  1
  •   Thorbjørn Ravn Andersen    15 年前

    问题出在天平的另一端。

    考虑一下如果你 小的 随机数。

    推荐文章