I have a number N e.g. 100 and I want to divide it into n parts (e.g. 10 parts)
Doing this linearly is trivial - N/n and I get 10 parts each of the value 10.
However, I would like to do this so that the parts are unequal and increase exponentially. E.g.
10, 30, 60 so the total is 100.
How can I write this as a javascript function?
function returnParts(desiredTotal, numParts) {
...
return parts ///return an array of parts
}
The function is simple enough, when you allow floating point numbers:
function getNums(n,f,tot){
let x=1;
const arr=[...new Array(n)]
.map(c=>x*=f);
const mul=tot/arr.reduce((a,c)=>a+c);
return arr.map(v=>mul*v)
}
console.log(getNums(3, 1.5, 100))
In order to get a unique result you need to specify the desired count n of numbers, the factor between the numbers f and the total tot the individual numbers must add up to.
And here is an adapted solution for integers:
function getNums(n,f,tot){
let x=1,res;
const arr=[...new Array(n)]
.map(c=>x*=f);
const mul=tot/arr.reduce((a,c)=>a+c);
res=arr.map(v=>Math.round(mul*v));
res[res.length-1]-=res.reduce((a,c)=>a+c)-tot;
return res
}
const ar=getNums(3, 1.5, 100);
console.log(ar,ar.reduce((a,c)=>a+c))
@Redu provided a formula for calculating the sum of the series 2**i for n values . By using the general annuity formula you will find that a suitable starting value x can be calculated through the following equation:
When I apply this formula I can save a few calculations in my script:
// small utility function
function sum(a,c){return a+c}
// create a series of n integers with
// factor b between them, having a total sum of tot:
function numSeries(b,n,tot){
let x=tot*(1-1/b)/(b**n-1)
const ar=[...new Array(n)]
.map(_=>Math.round(x*=b) );
// adjust the last number for rounding errors:
ar[n-1]=tot-ar.slice(0,-1).reduce(sum);
return ar;
}
// test it all:
const ar=numSeries(1.75,7,200);
console.log(ar,ar.reduce(sum))
This is a Math problem. Once you solve it, implementing this with JS or any other language is just calculation.
So you want K numbers summing to T. However they will increase exponentially. Not so clear but from your given example lets assume our exponential series to be
T = x + 2x + 4x + 8x + ... + 2^(n-1) x
We can apply summing series trick here like
2T = 2x + 4x + 8x + ... + 2^n x
Now;
2T = 2x + 4x + 8x + ... + 2^x
T = x + 2x + 4x + 8x + ... + 2^(n-1) x
(-)__________________________________
T = 2^n x - x = (2^n - 1) x
So;
T
x = _________
2^n - 1
The JS part.
function part(n,target){
var x = target / (2**n-1);
return Array.from({length:n}, (_,i) => x*2**i);
}
var result = part(6,100),
sum = result.reduce((p,c) => p+c);
console.log(result,sum);
This should do it. The exponential function is: A^numParts = desiredTotal. We first solve for A then push the values calculated values into the array. This works because the integral of an exponential function is the exponential function.
function returnParts (desiredTotal, numParts) {
var a = Math.pow(desiredTotal, 1/numParts)
var parts = []
for (var j = 0; j < numParts; j++) {
var part = Math.pow(a, j + 1) - Math.pow(a, j)
parts.push(part)
}
return parts
}
For example:
var results = returnParts(1000, 3)
console.log(results)
//
//returns [9.999999999999998, 89.99999999999997, 909.9999999999994]
// which is equal to ~1000
//