简体   繁体   English

具有固定总和的随机整数

[英]Random integer numbers with fixed sum

I'm trying to create a function that returns an array of random integer numbers whose sum is fixed.我正在尝试创建一个函数,该函数返回一个总和固定的随机整数数组。

Here is my code:这是我的代码:

 function arraySum(a) { return a.reduce((a, b) => a + b, 0) } function getRandomIntInclusive(min, max) { const minCeil = Math.ceil(min) const maxFloor = Math.floor(max) return Math.floor(Math.random() * (maxFloor - minCeil + 1)) + minCeil } function randomNumbersWithFixedSum(quantity, sum) { const randoms = [...Array(quantity - 1).keys()].map(q => getRandomIntInclusive(0, sum/quantity)) const last = sum - arraySum(randoms) return [...randoms, last] } console.log(randomNumbersWithFixedSum(1, 100)) console.log(randomNumbersWithFixedSum(2, 100)) console.log(randomNumbersWithFixedSum(3, 100)) console.log(randomNumbersWithFixedSum(4, 100)) console.log(randomNumbersWithFixedSum(5, 100))

It works but it's not exactly what I want.它有效,但不完全是我想要的。 I would like that each number is random in the range [0, sum] .我希望每个数字在[0, sum]范围内都是随机的。 In the randomNumbersWithFixedSum function I forced that the first (quantity-1) numbers are in [0, sum/quantity] , but I don't like.randomNumbersWithFixedSum函数中,我强制第一个(quantity-1)数字在[0, sum/quantity] ,但我不喜欢。

How can I create a really random numbers in [0, sum] whose sum is sum ?如何在[0, sum]创建一个真正的随机数,其总和为sum

This is a prime example where a recursive function can simplify the problem.这是递归函数可以简化问题的主要示例。 Each execution only calculates one random number and then calls itself with updated arguments.每次执行只计算一个随机数,然后用更新的参数调用自己。 See the comments for a description.有关说明,请参阅注释。

 function getRandomNumberBetweenIncluding(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } function randomNumbersWithFixedSum(quantity, sum) { // only a single number required; return the passed sum. if (quantity === 1) { return [sum]; } // Create one random number and return an array containing that number // as first item. Then use the spread operator and recursively execute // the function again with a decremented quantity and the updated // maximum possible sum. const randomNum = getRandomNumberBetweenIncluding(0, sum); return [ randomNum, ...randomNumbersWithFixedSum(quantity - 1, sum - randomNum), ]; } console.log(randomNumbersWithFixedSum(1, 100)); console.log(randomNumbersWithFixedSum(2, 100)); console.log(randomNumbersWithFixedSum(3, 100)); console.log(randomNumbersWithFixedSum(4, 100)); console.log(randomNumbersWithFixedSum(5, 100));

You could take only the rest of the sum for the max random number and shuffle the array later to omit large values only at the top of the array.您可以只取最大随机数的其余部分,然后对数组进行洗牌以仅在数组顶部省略大值

 function shuffle(array) { let i = array.length; while (--i) { let j = Math.floor(Math.random() * (i + 1)), temp = array[j]; array[j] = array[i]; array[i] = temp; } return array; } function getRandomIntInclusive(min, max) { const minCeil = Math.ceil(min) const maxFloor = Math.floor(max) return Math.floor(Math.random() * (maxFloor - minCeil + 1)) + minCeil } function randomNumbersWithFixedSum(length, sum) { length--; const randoms = Array.from({ length }, q => { const r = getRandomIntInclusive(0, sum) sum -= r; return r; }); return shuffle([...randoms, sum]); } console.log(randomNumbersWithFixedSum(5, 100)) console.log(randomNumbersWithFixedSum(4, 100)) console.log(randomNumbersWithFixedSum(3, 100)) console.log(randomNumbersWithFixedSum(2, 100)) console.log(randomNumbersWithFixedSum(1, 100))
 .as-console-wrapper { max-height: 100% !important; top: 0; }

What about the next solution:下一个解决方案呢:

  1. At the first iteration, we try to get a random number between 0 and max - say we retrieve N .在第一次迭代中,我们尝试获得一个介于0max之间的随机数 - 假设我们检索N
  2. At the second iteration - the max possible value cannot be greater than max - N (otherwise the sum will be greater than max ).在第二次迭代时 - 最大可能值不能大于max - N (否则总和将大于max )。
  3. Continue for quantity - 1 steps.继续quantity - 1步骤。
  4. At the last step we have to use what is left until the max在最后一步,我们必须使用剩​​下的直到max

 function getRandomIntInclusive(min, max) { const minCeil = Math.ceil(min) const maxFloor = Math.floor(max) return Math.floor(Math.random() * (maxFloor - minCeil + 1)) + minCeil } function randomNumbersWithFixedSum(quantity, sum) { const result = []; let total = 0; for (let i = 0; i < quantity - 1; i++) { let max = sum - total; let num = getRandomIntInclusive(0, max); result.push(num); total += num; } result.push(sum - total); return result; } console.log(randomNumbersWithFixedSum(1, 100)) console.log(randomNumbersWithFixedSum(2, 100)) console.log(randomNumbersWithFixedSum(3, 100)) console.log(randomNumbersWithFixedSum(4, 100)) console.log(randomNumbersWithFixedSum(5, 100))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM