我在生成不遵循离散均匀分布的随机数时遇到了麻烦。
例如,假设我有5个数字(为了保持简单),生成数字k的概率为k / 15。 (k = 1到5)
我的想法是使用rand()生成一个随机数j,如果这个数字j是:
1 =>然后生成数字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()更好的解决方案?
SO上有很多类似的问题......
cplusplus.com/reference/random/discrete_distribution/
相关的stackoverflow.com/questions/9432226/
你似乎走在正确的轨道上,但C ++已经有了一个专门的随机数分布,std::discrete_distribution
#include
#include
#include
#include
int main()
{
std::random_device rd;
std::mt19937 gen(rd());
// list of probabilities
std::vector 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 m;
for(int n=0; n<10000; ++n) {
++m[d(gen)];
}
for(auto p : m) {
std::cout << p.first <
";
}
}
在线演示:http://ideone.com/jU1ll
其他答案假设预期的分布与三角数的序列一起,但问题也指1-100和1-1000的范围,两者都不是三角形。 所以一般的答案似乎更合适。
@ shawnt00其他答案没有对输出范围做出这样的假设; 输出$ 1 $到$ 100范围内的数字,$他们将使用$ 100 $三角形数字。 但是,对于可以多次使用的固定分布,像这样的答案的方法可能仍然是一个不错的选择。
考虑从1到n的整数之和s是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);
}
注:这依赖于sqrt给出一个完美正方形的精确结果(例如,恰好返回精确为49的7)。这通常是一个安全的假设,因为IEEE 754要求精确舍入平方根。
IEEE 754双精度数可以表示从1到2 ^ 53的所有整数(以及许多更大的整数,但在2 ^ 53之后不连续)。所以这个函数应该适用于从1到floor((2^53 - 1) / 8) = 1125899906842623的所有s。
你可以利用以下奇怪的算术事实:
S(n) = 1 + 2 + 3 + ... + (n - 1) + n
或简化:
S(n) = n * (n + 1) / 2
这样可以避免存储阵列。