最大余额法-多个数据百分比和不为100%问题


一、简单介绍

最大余额法,又称余额制。是比例代表制投票制度下,一种议席分配的方法,相对于最高均数方法。

二、该方案的优缺点

以最大余额方法分配议席不算复杂,一般选民应该能够理解运作方法。使用黑尔数额的最大余额方法,并不偏重得票率较多或较少的名单,好处在于能给出中立、但同时具广泛代表性的选举结果。最大余额方法能包容少数派,有利发展多党派的议会。这种制度也令选民不能投票给个别候选人;从正面的角度看,这代表选民会改以各份参选名单的政纲为投票考虑依据,加强选举的理性基础。不过,各个政党可能会有相应的“配票策略”,例如将同党候选人分拆在不同的名单,好让候选人能通过余额数当选。

三、主要解决问题:处理多个数据计算百分比之和不为100%的问题

我们在工作中会遇到一些需要计算的问题,在多个数据计算各自的百分比时候会有一些问题,比如因为数据精度的保留和取舍引起的个数据百分比只和不为100%的情况。而为了解决此类问题,我们就发现可以用最大余额法的思想去解决该问题。但是相应的也会损失部分数据的精度。下面就让我们用代码来对最大余额法的算法进行实现吧。

/*
 * @Author: xuhao 
 * @Description 最大余额法(解决:计算百分比的时候不能相加等于百分之百)
 * @Date: 2020-06-30 14:26:02 
 * @Last Modified by: xuhao
 * @Last Modified time: 2020-07-07 10:00:05
 */

export function getPercentValue(valueList, idx, precision) {
    // 判断是否为空
    if (!valueList[idx]) {
        return 0;
    }
    // 求和
    var sum = valueList.reduce(function (acc, val) {
        return acc + (isNaN(val) ? 0 : val);
    }, 0)
    if (sum === 0) {
        return 0;
    }
    // 10的2次幂是100,用于计算精度。
    var digits = Math.pow(10, precision);
    // 扩大比例100,
    var votesPerQuota = valueList.map(function (val) {
        return (isNaN(val) ? 0 : val) / sum * digits * 100;
    })
    // 总数,扩大比例意味的总数要扩大
    var targetSeats = digits * 100;
    // 再向下取值,组成数组
    var seats = votesPerQuota.map(function (votes) {
        return Math.floor(votes);
    })
    // 再新计算合计,用于判断与总数量是否相同,相同则占比会100%
    var currentSum = seats.reduce(function (acc, val) {
        return acc + val;
    }, 0)
    // 余数部分的数组:原先数组减去向下取值的数组,得到余数部分的数组
    var remainder = votesPerQuota.map(function (votes, idx) {
        return votes - seats[idx];
    })
    // 给最大最大的余额加1,凑个占比100%;
    while (currentSum < targetSeats) {
        //  找到下一个最大的余额,给其加1
        var max = Number.NEGATIVE_INFINITY;
        var maxId = null;
        for (var i = 0, len = remainder.length; i < len; ++i) {
            if (remainder[i] > max) {
                max = remainder[i];
                maxId = i;
            }
        }
        // 对最大项余额加1
        ++seats[maxId];
        // 已经增加最大余数加1,则下次判断就可以不需要再判断这个余额数。
        remainder[maxId] = 0;
        // 总的也要加1,为了判断是否总数是否相同,跳出循环。
        ++currentSum;
    }
    // 这时候的seats就会总数占比会100%
    return seats[idx] / digits
}

声明:Xuhao's Blog|版权所有,违者必究|如未注明,均为原创|本网站采用BY-NC-SA协议进行授权

转载:转载请注明原文链接 - 最大余额法-多个数据百分比和不为100%问题


Carpe Diem and Do what I like