我想生成从 [a,b] 之间的特定分布(例如均匀随机)抽取的 N 个随机数,其总和为常数 C。我尝试了一些我自己能想到的解决方案,以及在类似线程上提出的一些解决方案,但是他们中的大多数要么适用于有限形式的问题,要么我无法证明结果仍然遵循所需的分布。
我尝试过的:
生成 N 个随机数,将它们全部除以它们的总和,然后乘以所需的常数。这似乎有效,但结果不遵循数字应在 [a:b] 范围内的规则。
生成 N-1 个随机数加上 0 和所需的常数 C 并对它们进行排序。然后计算每两个连续数字之间的差,差值就是结果。这再次求和为 C,但与上一个方法有相同的问题(范围可能大于 [a:b]。
我还尝试生成随机数,并始终以保留所需总和和范围的方式跟踪最小值和最大值,并得出以下代码:
bool generate(function<int(int, int)> randomGenerator,
int min, int max, int len, int sum,
std::vector<int> &output) {
/**
* Not possible to produce such a sequence
*/
if (min * len > sum)
return false;
if (max * len < sum)
return false;
int curSum = 0;
int left = sum - curSum;
int leftIndexes = len - 1;
int curMax = left - leftIndexes*min;
int curMin = left - leftIndexes*max;
for (int i = 0; i < len; i++) {
int num = randomGenerator((curMin < min) ? min : curMin,
(curMax > max) ? max : curMax);
output.push_back(num);
curSum += num;
left = sum - curSum;
leftIndexes--;
curMax = left - leftIndexes * min;
curMin = left - leftIndexes * max;
}
return true;
}
这似乎有效,但结果有时非常倾斜,我认为它不遵循原始分布(例如均匀分布)。例如:
//10 numbers within [1:10] which sum to 50:
generate(uniform, 1, 10, 10, 50, output);
//result:
2,7,2,5,2,10,5,8,4,5 => sum=50
//This looks reasonable for uniform, but let's change to
//10 numbers within [1:25] which sum to 50:
generate(uniform, 1, 25, 10, 50, output);
//result:
24,12,6,2,1,1,1,1,1,1 => sum= 50
注意输出中存在多少个。这听起来可能很合理,因为范围更大。但它们看起来确实不像均匀分布。
我不确定即使有可能实现我想要的目标,也许限制使问题无法解决。