Java: random integer with non-uniform distribution

前端 未结 11 1612
终归单人心
终归单人心 2020-12-13 12:55

How can I create a random integer n in Java, between 1 and k with a "linear descending distribution", i.e. 1 is

11条回答
  •  Happy的楠姐
    2020-12-13 13:24

    So we need the following distribution, from least likely to most likely:

    *
    **
    ***
    ****
    *****
    

    etc.

    Lets try mapping a uniformly distributed integer random variable to that distribution:

    1
    2  3
    4  5  6
    7  8  9  10
    11 12 13 14 15
    

    etc.

    This way, if we generate a uniformly distributed random integer from 1 to, say, 15 in this case for K = 5, we just need to figure out which bucket it fits it. The tricky part is how to do this.

    Note that the numbers on the right are the triangular numbers! This means that for randomly-generated X from 1 to T_n, we just need to find N such that T_(n-1) < X <= T_n. Fortunately there is a well-defined formula to find the 'triangular root' of a given number, which we can use as the core of our mapping from uniform distribution to bucket:

    // Assume k is given, via parameter or otherwise
    int k;
    
    // Assume also that r has already been initialized as a valid Random instance
    Random r = new Random();
    
    // First, generate a number from 1 to T_k
    int triangularK = k * (k + 1) / 2;
    
    int x = r.nextInt(triangularK) + 1;
    
    // Next, figure out which bucket x fits into, bounded by
    // triangular numbers by taking the triangular root    
    // We're dealing strictly with positive integers, so we can
    // safely ignore the - part of the +/- in the triangular root equation
    double triangularRoot = (Math.sqrt(8 * x + 1) - 1) / 2;
    
    int bucket = (int) Math.ceil(triangularRoot);
    
    // Buckets start at 1 as the least likely; we want k to be the least likely
    int n = k - bucket + 1;
    

    n should now have the specified distribution.

提交回复
热议问题