javascriptmathroundingpercentagetofixed

JavaScript - converting 3 numbers to percentage, doesn't yield 100% total


I have a scenario where I have three numbers:

  1. 17
  2. 10
  3. 90

I need to convert those into whole percentage values (so that when added, total 100% as you'd expect). I have this function:

function roundPercentageTotals(num1, num2, num3) {
    var total = num1 + num2 + num3;  // 117

    var num1Total = (num1 / total) * 100;  // 14.529914529914531
    var num2Total = (num2 / total) * 100;  //  8.547008547008546
    var num3Total = (num3 / total) * 100;  // 76.92307692307693

    var num1ToDecimal = num1Total.toFixed(1); // 14.5
    var num2ToDecimal = num2Total.toFixed(1); //  8.5
    var num3ToDecimal = num3Total.toFixed(1); // 76.9

    var totalPercentage = parseInt(num1ToDecimal) + parseInt(num2ToDecimal) + parseInt(num3ToDecimal); // 98

    return { percentage1: Math.round(num1ToDecimal, percentage2: Math.round(num2ToDecimal), percentage3: Math.round(num3ToDecimal) };
}

In my example, the total percentage calculated is 98%. Followed by:

  1. Percentage1 = 15
  2. Percentage2 = 9
  3. Percentage3 = 77

Which adds up to 101%, where am I going wrong?

Thanks for any help in advance!


Solution

  • Ok, so it looks like mathematically, I cannot achieve exactly what I was looking for. However, I needed to round figures up so it equalled 100% in the end (all be in that some of the figures where rounded, so not totally accurate).

    Here's my solution, just in case this is useful to someone else:

    function roundPercentageTotals(numArr) {
    
        // Total of all numbers passed.
        var total = numArr[0] + numArr[1] + numArr[2];
    
        // Percentage representations of each number (out of 100).
        var num1Percent = Math.round((numArr[0] / total) * 100);
        var num2Percent = Math.round((numArr[1] / total) * 100);
        var num3Percent = Math.round((numArr[2] / total) * 100);
    
        // Total percent of the 3 numbers combined (doesnt always equal 100%).
        var totalPercentage = num1Percent + num2Percent + num3Percent;
    
        // If not 100%, then we need to work around it by subtracting from the largest number (not as accurate but works out).
        if (totalPercentage != 100) {
            // Get the index of the largest number in the array.
            var index = getLargestNumInArrayIndex(numArr);
    
            // Take the difference away from the largest number.
            numArr[index] = numArr[index] - (totalPercentage - 100);
    
            // Re-run this method recursively, until we get a total percentage of 100%.
            return roundPercentageTotals(numArr);
        }
    
        // Return the percentage version of the array passed in.
        return [num1Percent, num2Percent, num3Percent];
    }
    
    function getLargestNumInArrayIndex(array) {
        return array.indexOf(Math.max.apply(Math, array));
    }
    

    Pass an array of the numbers into roundPercentageTotals, such as roundPercentageTotals([13,54,38]) and it will return the whole percentage (or nearest percentage I should say) figures in an array.