具有概率的随机数

2022-08-31 15:11:33

我想知道在特定范围内生成随机数的最佳方法(例如在Java中)是什么,其中每个数字都有一定的发生概率?

例如:

从 [1;3] 内生成随机整数,概率如下:

P(1) = 0.2
P(2) = 0.3
P(3) = 0.5


现在,我正在考虑在[0;100]内生成随机整数的方法,并执行以下操作:

如果它在[0;20]-->我得到了我的随机数1。
如果它在[21;50]-->我得到了我的随机数2。
如果它在[51;100]以内 -->我得到了我的随机数3。

你会怎么说?


答案 1

你的已经是一个很好的方法,适用于任何范围。

只是想:另一种可能性是通过用一个恒定的乘数乘法来摆脱分数,然后用这个乘数的大小构建一个数组。乘以你得到的10

P(1) = 2
P(2) = 3
P(3) = 5

然后,您创建一个具有反值的数组 - “1”进入元素1和2,“2”进入3到6,依此类推:

P = (1,1, 2,2,2, 3,3,3,3,3,3);

然后,您可以从此数组中选取一个随机元素。


(添加)使用kiruwka评论中示例中的概率:

int[] numsToGenerate           = new int[]    { 1,   2,    3,   4,    5   };
double[] discreteProbabilities = new double[] { 0.1, 0.25, 0.3, 0.25, 0.1 };

导致全整数的最小乘数是20,这给你

2, 5, 6, 5, 2

因此,的长度将为 20,具有以下值:numsToGenerate

1 1
2 2 2 2 2
3 3 3 3 3 3
4 4 4 4 4
5 5

分布完全相同:例如,“1”的几率现在是20分之2 - 仍然是0.1。

这是基于您的原始概率,所有概率加起来都为1。如果没有,则将总数乘以相同的因子(这也将是您的数组长度)。


答案 2

前段时间我写了一个帮助器类来解决这个问题。源代码应该足够清楚地显示概念:

public class DistributedRandomNumberGenerator {

    private Map<Integer, Double> distribution;
    private double distSum;

    public DistributedRandomNumberGenerator() {
        distribution = new HashMap<>();
    }

    public void addNumber(int value, double distribution) {
        if (this.distribution.get(value) != null) {
            distSum -= this.distribution.get(value);
        }
        this.distribution.put(value, distribution);
        distSum += distribution;
    }

    public int getDistributedRandomNumber() {
        double rand = Math.random();
        double ratio = 1.0f / distSum;
        double tempDist = 0;
        for (Integer i : distribution.keySet()) {
            tempDist += distribution.get(i);
            if (rand / ratio <= tempDist) {
                return i;
            }
        }
        return 0;
    }

}

该类的用法如下:

DistributedRandomNumberGenerator drng = new DistributedRandomNumberGenerator();
drng.addNumber(1, 0.3d); // Adds the numerical value 1 with a probability of 0.3 (30%)
// [...] Add more values

int random = drng.getDistributedRandomNumber(); // Generate a random number

测试驱动程序以验证功能:

    public static void main(String[] args) {
        DistributedRandomNumberGenerator drng = new DistributedRandomNumberGenerator();
        drng.addNumber(1, 0.2d);
        drng.addNumber(2, 0.3d);
        drng.addNumber(3, 0.5d);

        int testCount = 1000000;

        HashMap<Integer, Double> test = new HashMap<>();

        for (int i = 0; i < testCount; i++) {
            int random = drng.getDistributedRandomNumber();
            test.put(random, (test.get(random) == null) ? (1d / testCount) : test.get(random) + 1d / testCount);
        }

        System.out.println(test.toString());
    }

此测试驱动程序的示例输出:

{1=0.20019100000017953, 2=0.2999349999988933, 3=0.4998739999935438}

推荐