基于概率的随机数

时间:2012-06-08 02:21:35

标签: c++ random distribution probability

我无法生成不遵循离散均匀分布的随机数。

例如,假设我有5个数字(为了保持简单),生成数字k的概率为k / 15。 (k = 1到5)

我的想法是使用rand()生成一个随机数j,如果这个数字j是:

1 =>然后生成数字

2或3 => num 2

4或5或6 => num 3

7或8或9或10 => num 4

11或12或13或14或15 =>数字5

现在将其缩放为生成1-10,1-100,1-1000。这是否按照我打算的方式工作?我已经构建了一个循环,每次需要生成一个数字时都会这样做,我认为它可能是低效的,因为它一直上升,直到找到在其中一个范围内生成的j数.​​..有什么可能是更好的方法这样做?

编辑:或者用正确的数字创建一个数组,然后用rand()更好的解决方案拉出来?

3 个答案:

答案 0 :(得分:14)

你似乎走在正确的轨道上,但是C ++已经有了一个专门的随机数分布,std::discrete_distribution

#include <iostream>
#include <vector>
#include <map>
#include <random>

int main()
{
    std::random_device rd;
    std::mt19937 gen(rd());

    // list of probabilities    
    std::vector<double> p = {0, 1.0/15, 2.0/15, 3.0/15, 4.0/15, 5.0/15};
    // could also be min, max, and a generating function (n/15 in your case?)
    std::discrete_distribution<> d(p.begin(), p.end());

    // some statistics
    std::map<int, int> m;
    for(int n=0; n<10000; ++n) {
        ++m[d(gen)];
    }
    for(auto p : m) {
        std::cout << p.first << " generated " << p.second << " times\n";
    }
}

在线演示:http://ideone.com/jU1ll

答案 1 :(得分:10)

考虑从1到s的整数之和ns = n * (n + 1) / 2。求解n以获得n = (± sqrt(8*s + 1) - 1) / 2。我们可以忽略负平方根,因为我们知道n是正数。因此n = (sqrt(8*s + 1) - 1) / 2

因此,插入1到15之间s的整数:

s  n
01 1.000000
02 1.561553
03 2.000000
04 2.372281
05 2.701562
06 3.000000
07 3.274917
08 3.531129
09 3.772002
10 4.000000
11 4.216991
12 4.424429
13 4.623475
14 4.815073
15 5.000000

如果我们取每个计算的n(不小于n的最小整数)的上限,我们得到这个:

s  n
01 1
02 2
03 2
04 3
05 3
06 3
07 4
08 4
09 4
10 4
11 5
12 5
13 5
14 5
15 5

因此,你可以在恒定的空间和恒定的时间内从均匀分布到你的分布(没有迭代,也没有预先计算的表):

double my_distribution_from_uniform_distribution(double s) {
    return ceil((sqrt(8*s + 1) - 1) / 2);
}

N.B。这取决于sqrt给出一个完美正方形的精确结果(例如,恰好返回精确到49的7)。这通常是一个安全的假设,因为IEEE 754要求精确舍入平方根。

IEEE 754双精度数可以表示从1到2 ^ 53(以及许多更大的整数,但在2 ^ 53之后不连续)的所有整数。因此,此功能应适用于从1到s的所有floor((2^53 - 1) / 8) = 1125899906842623

答案 2 :(得分:0)

你可以利用以下奇怪的算术事实:

S(n) = 1 + 2 + 3 + ... + (n - 1) + n

或简化:

S(n) = n * (n + 1) / 2

这可以避免存储数组。