【发布时间】:2015-05-25 01:45:32
【问题描述】:
我想从 [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
注意输出中有多少个。这听起来可能是合理的,因为范围更大。但它们看起来并不像均匀分布。 我不确定即使有可能实现我想要的,也可能是限制因素使问题无法解决。
【问题讨论】:
-
那叫蛮力!你知道当输入长度很大时可能需要很长时间!
-
请注意,生成数字的函数可能会失败:它仅在 Na b 时有效。这看起来是一个有趣的问题。最终的解决方案需要返回一个错误代码来表明问题是否可以解决。
-
@juhist 这就是我在函数中返回 bool 的原因。并且我在函数的请求中检查了可能性!
-
逻辑上不可能解决“我想从 [a,b] 之间的特定分布(例如均匀随机)中抽取 N 个随机数,总和为常数 C。” - 那么你能解释一下你希望通过这样做解决什么更高层次的问题吗?可能有一个替代方案可以解决这个问题? (鉴于您可以在这里找到答案,可能值得将这个问题保持原样,并询问如何解决您的外部问题)
-
如果你愿意妥协,那么最简单的选择就是不要担心达到一个不可能的目标。让你的约束之一溜走。我建议您最初的重新缩放解决方案(让尺寸范围滑动)那时可以正常工作。如果您想要某种相同的工作负载进行比较,请将您的随机数生成器作为测试设置的一部分。
标签: c++ algorithm random sum range