Search code examples
javamathrandomdistributionlogarithm

Java: Generating a random numbers with a logarithmic distribution


I am attempting to generate a random numbers with a logarithmic distribution.

Where n=1 occurs half of the time, n=2 occurs a quarter of the time, n=3 occurs an eighth of the time, etc.

    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);

Most of the time, I am getting the result I need, however once every so often, I get a value of n that is larger than maxN.

Why is this so? The way I see it, the max value of Math.random() is 1.0;
therefore the max value of (Math.random() * t)) is t;
therefore the max value of log2(t) is maxN, since t = 2^maxN;

Where has my logic gone off track?

Thanks


Solution

  • logarithm of numbers less than 1.0 is negative. When the random number generated is such that it is less than 1.0, the expression ((int) (Math.log(Math.random() * t) / Math.log(2))) is a negative number and hence maxN - (the negative number) is more than maxN.

    The following expression should give correct distribution.

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

    Note that:

    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