I've been breaking my head in trying to calculate the proportional scaling of percentages, in which the end result should always quantify to 100%.
For example:
Person A - 60%
Person B - 40%
When adding person C with 50%, the following scaling occurs, in proportion to their original percentage of what's left:
Person A: 30%
Person B: 20%
Person C: 50%
When amending an entry; for example, setting Person A to 10%, the following occurs:
Person A: 10%
Person B: 30%
Person C: 60%
I was able to calculate this off the top of my head (strange – that never works), however I'm uncertain as to how to apply this in mathematical formula, and in its simplest form; in such a way that the calculation works in all scenarios, whether adding, amending or removing persons and their percentages.
At every calculation, I have existing reference to the following:
- How many items (persons) there currently are
- The original percentage allocated to that person
Your help would be greatly appreciated.
Edit
I'm not sure how to explain it in a better form, but I hope the following tables may explain a bit better:
Where ? are the values to be calculated
The closest I've come so far:
var beneficiaries = [
100
]; // Current state of beneficiaries
const calculateBeneficiaryRatio = (action, value = 0, index = 0) => {
let results = [];
let cur_percentage, new_percentage;
switch(action) {
case "add":
for(let i in beneficiaries) {
cur_percentage = beneficiaries[i];
new_percentage = (100 - value) * (cur_percentage / 100);
beneficiaries[i] = new_percentage;
}
beneficiaries.push(value);
return beneficiaries;
break;
case "remove":
value = beneficiaries[index];
beneficiaries.splice(index, 1);
for(let i in beneficiaries) {
cur_percentage = beneficiaries[i];
new_percentage = cur_percentage + (value / beneficiaries.length);
beneficiaries[i] = new_percentage;
}
return beneficiaries;
break;
case "update":
beneficiaries[index];
for(let i in beneficiaries) {
cur_percentage = beneficiaries[i];
new_percentage = (100 - value) * (cur_percentage / 100) + (value / beneficiaries.length);
beneficiaries[i] = new_percentage;
}
return beneficiaries;
break;
}
}
beneficiaries = calculateBeneficiaryRatio('add', 29);
console.log(beneficiaries);
beneficiaries = calculateBeneficiaryRatio('add', 20);
console.log(beneficiaries);
beneficiaries = calculateBeneficiaryRatio('remove', null, 1);
console.log(beneficiaries);
beneficiaries = calculateBeneficiaryRatio('update', 20, 0);
console.log(beneficiaries);
Best Answer
Neither of your two examples matches your description: instead of $(85,5,10)$, I would have expected $(81,9,10)$, because that preserves the ratio $a:b$, i.e., $90:10=81:9$. Maybe there was a miscalculation?
If that's the case, then here's the idea: suppose you have some percentages $(a,b,c,d)$ and you're changing $d$ to $d+\Delta$. Then we need to remove a total of $\Delta$ from the other three while preserving the ratio $a:b:c$.
Looking at $a$ as a fraction of $a+b+c$, we have $\frac a{a+b+c}$. This is the fraction of $\Delta$ by which $a$ must decrease, so the new value of $a$ will be $$a - \left(\frac a{a+b+c}\right)\Delta,$$ which after factoring out the $a$ we can rewrite as $$a\left(1 - \frac \Delta{a+b+c}\right).$$
To put it more simply, let $T$ be the total of the first three values: $T=a+b+c$. Then the new value of $a$ will be $a\left(\frac{T-\Delta}T\right).$
The changes to $b$ and $c$ are similar; therefore, the new values of $(a,b,c,d)$ will be $$\left(a\left(\frac{T-\Delta}T\right), b\left(\frac{T-\Delta}T\right), c\left(\frac{T-\Delta}T\right), d + \Delta\right).$$
Finally, note that the case $a=b=c=0$ will have to be given special treatment.