js拆分百分数_一组数据百分比的优化算法(js)

一组数据百分比的优化算法(js)

在图表计算百分比时,经常遇到百分比的和不等于1。比如一组数据[1,1,1],计算的百分比结果为 [33%, 33%, 33%],百分比的和为99%,不等于1。计算百分比保留位数时经常需要四舍五入,从而产生误差,同时可能会出现百分比整体不为1的情况。我们可以依次调整误差较大的百分比,使百分比总和为1。以[3, 1, 5, 9]这组数据为例,具体步骤如下:计算出各项百分比。

0: 17%;1: 6%;2: 28%;3: 50%计算百分比的和。

17% + 6% + 28% + 50% = 101%101% > 1,超出1%。可以通过保留百分比的更多位数来计算每个百分比的误差。然后根据误差大小排序。

排序前:

[0]:17%,[1]:6%,[2]:28%,[3]:50%

计算误差:

[0]:17% - 16.67% = 0.33%

[1]:6% - 5.56% = 0.44%,

[2]:28% - 27.78% = 0.22%,

[3]:50% -50.00% = 0.00%

排序后:[1]:6%,[0]:17%,[2]:28%,[3]:50%

百分比总和超出了1%,排序后的百分比依次减少最小精度值(1%),减少超出值,直到百分比总和等于1。(该示例中只超出了1%,只需减少第1个值即可)

[1]:6% - 1% = 5% 超出0%,百分比总和为1,结束。

[0]:17%,

[2]:28%,

[3]:50%

5)最后结果为:

[0]:17%,[1]:5%,[2]:28%,[3]:50%

js的代码实现:

/*** @param { Array } arr 一组数据* @param { Boolean } needSign 返回值是否添加%* @param { Number } decimalCount 精度:最多保留多少位小数* @returns { Array }*/

const calcPercentage = (arr = [], needSign = true, decimalCount = 4) => {

let sum = arr.reduce((a, b) => a + b, 0),

D = decimalCount < 2 ? 2 : decimalCount,

// E1, E2将小数转化成整数,解决因精度导致小数计算错误的问题 E1 = Math.pow(10, D),

E2 = Math.pow(10, D + 2);

if(sum === 0) {

return arr.map(_ => needSign ? '0%' : 0);

}

const perArr = arr.map((e, i) => ({

index: i,

percentage: Math.round((e / sum).toFixed(D) * E1)

}));

const all = perArr.reduce((a, b) => a + b.percentage, 0);

// 比较计算出的百分比总和和实际总和 if(all > E1) {

// 根据误差大小排序 perArr.sort((a, b) => {

const aCur = a.percentage * Math.pow(10, 2),

aReal = Number((arr[a.index] / sum).toFixed(D + 2)) * E2,

bCur = b.percentage * Math.pow(10, 2),

bReal = Number((arr[b.index] / sum).toFixed(D + 2)) * E2,

aError = aCur - aReal,

bError = bCur - bReal;

return bError - aError < 0 ? -1 : bError - aError > 0 ? 1 : a.index - b.index; // 根据误差排序,如果误差一样,索引小的在前面 });

let sumError = all - E1, i = 0;

// 百分比总和多的部分,从误差大的百分比依次扣除 while(sumError) {

perArr[i].percentage = perArr[i].percentage - 1;

sumError--;

i++;

}

}

if(all < E1) {

debugger;

// 根据误差大小排序 perArr.sort((a, b) => {

const aCur = a.percentage * Math.pow(10, 2),

aReal = Number((arr[a.index] / sum).toFixed(decimalCount + 2)) * E2,

bCur = b.percentage * Math.pow(10, 2),

bReal = Number((arr[b.index] / sum).toFixed(decimalCount + 2)) * E2,

aError = aCur - aReal,

bError = bCur - bReal;

return aError - bError < 0 ? -1 : aError - bError > 0 ? 1 : a.index - b.index;

});

let sumError = all - E1, i = 0;

// 百分比总和少的部分,从误差大的百分比依次补上 while(sumError) {

perArr[i].percentage = perArr[i].percentage + 1;

sumError++;

i++;

}

}

return perArr.sort((a, b) => a.index - b.index).map(e => needSign ? (e.percentage / Math.pow(10, D - 2)).toFixed(D - 2) + '%' : e.percentage/E1);

};

  • 0
    点赞
  • 1
    收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weixin_39612733

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值