I want a bit of javascript that will allow me to generate 4 random numbers that add up to a certain value e.g.
if
max = 20
then
num1 = 4
num2 = 4
num3 = 7
num4 = 5
or
max = 36
then
num1 = 12
num2 = 5
num3 = 9
num4 = 10
What I have so far is...
var maxNum = 20;
var quarter;
var lowlimit;
var upplimit;
var num1 = 1000;
var num2 = 1000;
var num3 = 1000;
var num4 = 1000;
var sumnum = num1+num2+num3+num4;
quarter = maxNum * 0.25;
lowlimit = base - (base * 0.5);
upplimit = base + (base * 0.5);
if(sumnum != maxNum){
num1 = Math.floor(Math.random()*(upplimit-lowlimit+1)+lowlimit);
num2 = Math.floor(Math.random()*(upplimit-lowlimit+1)+lowlimit);
num3 = Math.floor(Math.random()*(upplimit-lowlimit+1)+lowlimit);
num4 = Math.floor(Math.random()*(upplimit-lowlimit+1)+lowlimit);
}
This code will create four integers that sum up to the maximum number and will not be zero
var max = 36;
var r1 = randombetween(1, max-3);
var r2 = randombetween(1, max-2-r1);
var r3 = randombetween(1, max-1-r1-r2);
var r4 = max - r1 - r2 - r3;
function randombetween(min, max) {
return Math.floor(Math.random()*(max-min+1)+min);
}
EDIT: And this one will create thecount
number of integers that sum up to max
and returns them in an array (using the randombetween
function above)
function generate(max, thecount) {
var r = [];
var currsum = 0;
for(var i=0; i<thecount-1; i++) {
r[i] = randombetween(1, max-(thecount-i-1)-currsum);
currsum += r[i];
}
r[thecount-1] = max - currsum;
return r;
}
For my own project, I found another solution that maybe it's helpful for other people.
The idea is to let all numbers have the same probability... The first thing that came to my mind was creating an array [1,2,3,..,N,undefined,undefined,....]
of length max
, shuffle it, and get the positions of 1,2,3,...,N
with indexOf
, but this was slow for big numbers.
Finally I found another solution I think it's right: Create N
random numbers between 0 and 1, and this is the part of the fraction "they want to take". If all numbers pick the same number (p.e. 1) they all will get the same value.
Code, based on the solution of @devnull69:
function generate(max, thecount) {
var r = [];
var currsum = 0;
for(var i=0; i<thecount; i++) {
r.push(Math.random());
currsum += r[i];
}
for(var i=0; i<r.length; i++) {
r[i] = Math.round(r[i] / currsum * max);
}
return r;
}
EDIT: there's a problem with this solution with Math.round. Imagine we want 4 numbers that add up to 20, and get this numbers before doing Math.round:
7.4 3.4 5.7 3.3
If you add them, they sum 20. But if you apply Math.round:
7 3 6 3
Which they add to 18.
Then in my project, I had to do another round to give those "missing" values to the numbers that have a higher decimal fraction. This gets more complex, like:
function generate(max, thecount) {
var r = [];
var decimals = [];
var currsum = 0;
for(var i=0; i<thecount; i++) {
r.push(Math.random());
currsum += r[i];
}
var remaining = max;
for(var i=0; i<r.length; i++) {
var res = r[i] / currsum * max;
r[i] = Math.floor(res);
remaining -= r[i];
decimals.push(res - r[i]);
}
while(remaining > 0){
var maxPos = 0;
var maxVal = 0;
for(var i=0; i<decimals.length; i++){
if(maxVal < decimals[i]){
maxVal = decimals[i];
maxPos = i;
}
}
r[maxPos]++;
decimals[maxPos] = 0; // We set it to 0 so we don't give this position another one.
remaining--;
}
return r;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With