我在想,无论如何都要生成一组随机数,其总和始终是常数。例如,20可以分成5个数字(1,2,3,4,10)我不关心5个数字中的每个是什么,只要它们的总和等于20.无论如何以编程方式这样做?
答案 0 :(得分:15)
要获得均匀分布,诀窍是将总和视为数字线,而不是为分段生成随机数,生成n-1个数字作为沿线的点,并减去得到分段。以下是ojrandlib的功能:
static int compare(const void *a, const void *b) {
return *(int*)a - *(int*)b;
}
void ojr_array_with_sum(ojr_generator *g, int *a, int count, int sum) {
int i;
for (i = 0; i < count-1; ++i) { a[i] = ojr_rand(g, sum+1); }
qsort(a, count-1, sizeof(int), compare);
a[count-1] = sum;
for (i = count-1; i > 0; --i) { a[i] -= a[i-1]; }
}
ojr_rand(g, limit)
生成从0到limit-1的均匀随机整数。然后,此函数使用添加到a
的{{1}}个随机整数填充数组count
。不应该太难以适应任何其他RNG。
答案 1 :(得分:1)
此方法可以完成这项工作,还可以控制值之间的“差异度”(例如,如果您希望数组值彼此接近)
/**
* Create array of positive integers which exactly sums to a given (integer) number.
* @param {Number} number of items
* @param {Number} sum required sum
* @param {Number} [d=100] difference degree between the values (0..100)
*/
randomSumArray: function(len, sum, d) {
var _sum = 0;
var arr = [];
var n, i;
if (!d && d !== 0) {
d = 100;
}
for (i = 0; i < len; i++) {
var from = (100 - d) * 1000,
to = (100 + d) * 1000,
n = Math.floor(Math.random() * (to - from + 1) + from); //random integer between from..to
_sum += n;
arr.push(n);
}
var x = sum / _sum;
_sum = 0; //count sum (again)
for (var i = 0; i < len; i++) {
arr[i] = Math.round(arr[i] * x);
_sum += arr[i];
}
var diff = sum - _sum;
// Correct the array if its sum does not match required sum (usually by a small bit)
if (diff) {
x = diff / Math.abs(diff); //x will be 1 or -1
var j = 0;
while (diff && j < 1000) { //limit to a finite number of 'corrections'
i = Math.floor(Math.random() * (len + 1)); //random index in the array
if (arr[i] + x >= 0) {
arr[i] += x;
diff -= x;
}
j++;
}
}
return arr;
}
答案 2 :(得分:0)
这有点诡计但仍然是:) 我提出这个可能的想法,而不是说它是最好的 (而且大多数情况下,你需要整数,所以它无论如何都不会工作)
如果所需的随机数不是必需整数:
那么你可以在[0,1]之间生成N个随机数,然后将数组规范化为你的S:)
for(i=0; i<N; i++)
arr[i] = rand;
cursum = 0;
for(i=0; i<N; i++)
cursum+=arr[i];
norm = S / cursum;
for(i=0; i<N; i++)
arr[i] *= norm;
答案 3 :(得分:0)
如果生成的数字不是必需的正数或在某个范围内 你可以计算最后一个数字 S - SUM(A1..A [N-1])
N-1随机数的选择显然是均匀的,
因为最后一个数字无论如何都取决于其余的数字
(每组最后一个号码只有一个选项)。
一致性不受阻碍。
Arr = new int[N];
int sum=0;
for(i=0; i<N-1; i++)
{
int x = getRandomInt();
sum += x;
Arr[i] = x;
}
Arr[N-1] = S - sum;
return Arr;
答案 4 :(得分:0)
在我的情况下,我必须对值数组执行此操作,这需要Sum并将其随机分成数字范围。
<html>
<script type="text/javascript">
function f(){
var array = [{
order: '1-2480831',
value: 2040
}, {
order: 'BAESYS-2012-0001',
value: 570
}, {
order: 'BAESYS-2012-0002',
value: 773
}, {
order: '1-3840231',
value: 299
}, {
order: '1-3840298',
value: 1609
}, {
order: '1-3841519',
value: 1940
}];
var splitInto = 3;
document.write("[");
for (i=0; i<array.length; i++)
{
document.write("{ Id : '"+array[i].order+"', Data : [");
var result = RandGenerator(splitInto,array[i].value);
var sum = 0;
for(ii =0;ii<result.length; ii++){
sum += result[ii];
document.write(result[ii]+',');
}
document.write("]},");
}
document.write("]");
}
function RandGenerator(count, sum) {
var a = [];
for (iii = 0; iii < count-1; iii++)
{
a[iii] = getRandToValue(sum);
sum -= a[iii];
}
a[count-1] = sum;
return a;
}
function getRandToValue(maxRand)
{
var random = Math.random();
var computed = (maxRand)*random;
return computed;
}
f();
</script>
</html>
答案 5 :(得分:-1)
使用库函数获取随机数。
现在您想要的随机数是生成的随机数mod,即允许的总和。
接下来,您将允许的总和减去刚刚生成的数字。
假设你的库随机数生成器返回的第一个随机数是109。
所以你的第一个随机数是109 mod 20 = 9.将你允许的总数更新为20 -9 = 11.
你继续前进,直到你允许的金额为零。
请注意,我假设你提到的数字5只是一个例子。如果您希望随机数的数量正好为5,则可能需要修改此方法。
答案 6 :(得分:-1)
是的!试试这个算法
num1=rand()%20;
num2=rand()%(20-num1);
num3=rand()%(20-num1-num2);
num4=rand()%(20-num1-num2-num3);
num5=20-num4-num3-num2-num1;
所以确定五个数字是随机的,它们总计为20 [ 如果您需要 ]
,可以使用循环执行此操作一般情况下,您可以先随机生成数字[n]的数量,这些数字将总计为手中的数字[K]
n=rand()%k;--assuming the number of rand numbers you want are between 1 and k[sum]
n1=rand()%k;
n2=rand()%(k-n1)
.
.
nn-1=rand()%(k-n1...-nn-2)
nn=k-n1-n2...nn-1
我希望这会对你有所帮助!