我想生成N个随机数,这些随机数来自于特定的分布(例如均匀分布),在[a,b]之间,并且它们的和为常数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
请注意输出中存在多少个 "1"。这听起来可能是合理的,因为范围更大。但它们看起来并不像是均匀分布。 我不确定是否可能实现我想要的,也许限制使问题无法解决。
N
和C
会有多大? - rici