Kotlin版本的最大余额法实现(网上有Java版,解决百分比相加结果不等于100%)

object PercentKit {
    /**
     * 修复百分比结果相加不等于100的问题
     * @param arr 原始值的数组
     * @param sum 原始值之和
     * @param idx 当前位置索引
     * @param scale 精度
     *
     * @return 返回结果乘以100后的值,比如 0.333 返回 33.3
     */
    fun getPercentValue(arr: List, sum: Double, idx: Int, scale: Int): Double {
        var sum = sum
        if (arr.size - 1 < idx) {
            return 0.0.round(scale)
        }
        //求和
        if (sum <= 0) {
            for (i in arr.indices) {
                sum += arr[i]
            }
        }
        //10的2次幂是100,用于计算精度。
        val digits = 10.0.pow(scale.toDouble())
        //扩大比例100
        val votesPerQuota = DoubleArray(arr.size)
        for (i in arr.indices) {
            val `val` = arr[i] / sum * digits * 100
            votesPerQuota[i] = `val`
        }
        //总数,扩大比例意味的总数要扩大
        val targetSeats = digits * 100
        //再向下取值,组成数组
        val seats = DoubleArray(arr.size)
        for (i in votesPerQuota.indices) {
            seats[i] = floor(votesPerQuota[i])
        }
        //再新计算合计,用于判断与总数量是否相同,相同则占比会100%
        var currentSum = 0.0
        for (i in seats.indices) {
            currentSum += seats[i]
        }
        //余数部分的数组:原先数组减去向下取值的数组,得到余数部分的数组
        val remainder = DoubleArray(arr.size)
        for (i in seats.indices) {
            remainder[i] = votesPerQuota[i] - seats[i]
        }
        while (currentSum < targetSeats) {
            var max = 0.0
            var maxId = 0
            for (i in remainder.indices) {
                if (remainder[i] > max) {
                    max = remainder[i]
                    maxId = i
                }
            }
            //对最大项余额加1
            ++seats[maxId]
            //已经增加最大余数加1,则下次判断就可以不需要再判断这个余额数。
            remainder[maxId] = 0.0
            //总的也要加1,为了判断是否总数是否相同,跳出循环。
            ++currentSum
        }
        // 这时候的seats就会总数占比会100%
        return seats[idx] / digits
    }
}

你可能感兴趣的:(Kotlin版本的最大余额法实现(网上有Java版,解决百分比相加结果不等于100%))