我无法生成不遵循离散均匀分布的随机数。
例如,假设我有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()更好的解决方案拉出来?
答案 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";
}
}
答案 1 :(得分:10)
考虑从1到s
的整数之和n
为s = 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
这可以避免存储数组。