美文网首页
最大余额法(计算百分比)

最大余额法(计算百分比)

作者: codingZero | 来源:发表于2023-03-20 15:15 被阅读0次

假设有数组 array = [7, 18, 23, 17]
要求计算每个数字占总和的百分比

普通计算方式

  1. 计算总和 7 + 18 + 23 + 17 = 65

  2. 每个数依次除以总和并乘以100
    7 / 65 * 100 = 10.76923076923077
    18 / 65 * 100 = 27.692307692307693
    23 / 65 * 100 = 35.38461538461539
    17 / 65 * 100 = 26.153846153846157

  3. 四舍五入保留两位小数
    10.76923076923077 => 10.77
    27.692307692307693 => 27.69
    35.38461538461539 => 35.38
    26.153846153846157 => 26.15

最终结果 10.77 + 27.69 + 35.38 + 26.15 = 99.99 < 100

完整代码
let array = [7, 18, 23, 17]
let sum = array.reduce((total, value) => total + value)
let result = array.map(val => ((val / sum) *100).toFixed(2)) 

为了解决上面的问题,于是就有了最大余额法,至于什么是最大余额法,百度上有,这里只讲过程

最大余额法

  1. 计算总和 7 + 18 + 23 + 17 = 65

  2. 计算总份额
    由于计算的是百分比,所以需要扩大100倍
    百分比保留两位小数,所以再扩大100倍(三位小数就是1000倍)
    所以总份额为 100 * 100 = 10000

  3. 按比例分配份额
    7 / 65 * 10000 = 1076.923076923077
    18 / 65 * 10000 = 2769.2307692307693
    23 / 65 * 10000 = 3538.461538461539
    17 / 65 * 10000 = 2615.3846153846157

  4. 取分配份额的整数部分 [1076, 2769, 3538, 2615]
    1076 + 2769 + 3538 + 2615 = 9998 < 10000
    10000 - 9998 = 2 因此还剩两份需要分配

  5. 取分配份额的小数部分 [0.923076923077, 0.2307692307693, 0.461538461539, 0.3846153846157]
    找出小数部分最大的两个数(剩几份找几个),下标分别为0 和 2

  6. 为整数部分下标为0 和 2的数各加上1
    [1076 + 1, 2769, 3538 + 1, 2615] => [1077, 2769, 3539, 2615]

  7. 除以100得到最终的百分比
    因为保留2位小数,之前乘以了100,所以最后要除以100
    [1077, 2769, 3539, 2615] / 100 => [10.77, 27.69, 35.39, 26.15]

最终结果 10.77 + 27.69 + 35.39 + 26.15 = 100

完整代码
const getPercentValue = (array, precision = 2) => {
  // 如果不是数字则赋值为0
  let arrayList = array.map(value => (isNaN(value) ? 0 : value))
  // 计算总和
  let sum = arrayList.reduce((total, value) => total + value)
  // 0不能做除数,直接返回
  if (sum === 0) return
  // 小数位扩大倍数
  let digits = Math.pow(10, precision)
  // 总份额
  let total = digits * 100
  // 分配份额
  let shareList = arrayList.map(val => (val / sum) * total)
  // 取整数部分
  let integerList = shareList.map(val => Math.trunc(val))
  // 计算整数部分的总和
  let shareSum = integerList.reduce((total, val) => total + val)
  // 取小数部分
  let decimalsList = shareList.map((value, index) => value - integerList[index])
  // 整数部分总和小于总份额时
  while (shareSum < total) {
    let max = decimalsList[0]
    let maxIndex = 0
    // 找出小数位最大的下标
    for (let i = 1; i < decimalsList.length; i++) {
      if (decimalsList[i] > max) {
        max = decimalsList[i]
        maxIndex = i
      }
    }
    // 小数位最大的加1
    integerList[maxIndex] += 1
    // 加1后小数清零,不参与下次比较
    decimalsList[maxIndex] = 0
    // 总数也需要加1
    shareSum += 1
  }
  // 返回每项占比
  return integerList.map(value => (value / digits).toFixed(precision))
}

相关文章

网友评论

      本文标题:最大余额法(计算百分比)

      本文链接:https://www.haomeiwen.com/subject/bdgurdtx.html