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].
In the randomNumbersWithFixedSum function I forced that the first (quantity-1) numbers are in [0, sum/quantity], but I don’t like.

How can I create a really random numbers in [0, sum] whose sum is sum?

Stack Overflow Asked by whitecircle on December 28, 2020

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));

Correct answer by str on December 28, 2020

1. At the first iteration, we try to get a random number between 0 and max - say we retrieve N.
2. At the second iteration - the max possible value cannot be greater than max - N (otherwise the sum will be greater than max).
3. Continue for quantity - 1 steps.
4. At the last step we have to use what is left until the 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))

Answered by falinsky on December 28, 2020

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; }

Answered by Nina Scholz on December 28, 2020

Related Questions

Hexagon grid with border and image responsive (clip path probably)

2  Asked on December 22, 2021

Find a cell containing a specific date

1  Asked on December 22, 2021

1  Asked on December 22, 2021 by kyu96

Unable to remove event listener from document

1  Asked on December 22, 2021 by prawn

Invalid result adding the number of 1s in a binary number

2  Asked on December 20, 2021 by aworeham

How to check if arraylist tree in Java is empty or not?

2  Asked on December 20, 2021

How to print the elements of 3 different arrays by the order?

2  Asked on December 20, 2021 by fuzzyfiso

Finding string elements of an array in another array

5  Asked on December 20, 2021 by p-emt

Python SyntaxError vs TypeError for repeated keyword arguments

1  Asked on December 20, 2021

How to plot several columns on the same line chart in R?

2  Asked on December 20, 2021 by user13953317

Is there a way to craft URLs to fill forms faster?

1  Asked on December 20, 2021 by rosalind-goh

How to merge dictionaries in np.ndarray into one dictionary?

1  Asked on December 20, 2021 by el_1988

how to not use the default PHP 7.3 of Mac OSX Catalina 10.15.6 and use home brew php?

2  Asked on December 20, 2021

Using BeautifulSoup to get the text after a strong tag, when that text is not within a … itself

1  Asked on December 20, 2021 by papelr

Is it bad practice to return an array of objects directly?

2  Asked on December 20, 2021

SQL Server: update on single record only updated half the varchar content

2  Asked on December 20, 2021

How to decode hexadecimal string with “b” at the beggining?

1  Asked on December 20, 2021 by ger-cas

infinite loop while using useEffect and redux store

0  Asked on December 20, 2021 by susanta

Cannot convert textfield into string

1  Asked on December 20, 2021 by anuj-amin

Is there multiple ways to cin vector elements?

1  Asked on December 20, 2021 by 2kbummer