如何处理不是100的舍入百分比之和?

时间:2011-03-08 01:06:38

标签: ruby rounding

假设我们有一个带整数的项目列表:

USA:       3 people
Australia: 2 people
Germany:   2 people

如果我们计算每个值与整个列表中总和的百分比,我们得到:

USA:       3/(3+2+2)*100 = 42.857...%
Australia: 2/(3+2+2)*100 = 28.571...%
Germany:   2/(3+2+2)*100 = 28.571...%

如果我们绕过它,我们得到:

USA:       43%
Australia: 29%
Germany:   29%

总和43 + 29 + 29 = 101不是100,对软件用户来说看起来有点奇怪。你会如何解决这个问题?

5 个答案:

答案 0 :(得分:27)

您可以参考选举中使用的最大剩余方法:Wikipedia: Largest Remainder Method

在你的情况下,你有

USA:       42.857...
Australia: 28.571...
Germany:   28.571...

如果你取整数部分,你得到

USA:       42
Australia: 28
Germany:   28

最多可以增加98,你想再增加两个。现在,您查看小数部分,即

USA:       0.857...
Australia: 0.571...
Germany:   0.571...

并取最大值,直到总数达到100.如果你带美国,总数就会达到99,你想再拿一个。这里出现了问题。由于您在澳大利亚和德国之间保持0.571的平局,如果您同时选择两者,则总数将为101.所以您有两种方式可供选择:

(a)如果你强烈要求总数为100,那就去澳大利亚吧,不要再采取行动了:

USA:       43
Australia: 29
Germany:   28

(b)如果你更愿意尊重澳大利亚和德国并列的事实,那你就停止了:

USA:       43
Australia: 28
Germany:   28

答案 1 :(得分:12)

选项1

如果你担心结果对用户来说有点奇怪,我会在结果上加上一个脚注,提到百分比已经四舍五入,而我的总数不是100%。只有在舍入导致此行为时,您才能以编程方式显示消息。

USA percentage:       43
Australia percentage: 29
Germany percentage:   29

*Percentages may not total 100 due to rounding

选项2

由于您使用的是Ruby,我建议使用rational个数字。这样您就不会在需要时失去精度。您可以使用旁边的有理数字显示百分比,而不是脚注,如下所示:

USA percentage:       43 (3/7)
Australia percentage: 29 (2/7)
Germany percentage:   29 (2/7)

选项3

包含更多小数位,以便舍入误差不那么严重:

USA percentage:       42.9
Australia percentage: 28.6
Germany percentage:   28.6

这导致100.1而不是101。

答案 2 :(得分:4)

由于四舍五入,组件可能不会合计为总数。 统计报告中的标准。

在下一张桌子,报告或附录中,作弊会回来咬你。您无法跟踪更改。对于那些没有阅读过这类报道的人来说,这看起来很有趣。

噢,是的。它不是一个舍入错误。

答案 3 :(得分:3)

你可以通过对所有舍入结果进行求和来“欺骗”一点,但是最后一个给予最后一个值100 - 前一个总和......

在这种情况下,您将拥有:

USA = 43
Aus = 29
Ger = 28  (100 - (43 + 29))

但这只是一个肮脏的伎俩...你应该遵循马特给出的更诚实/准确的解决方案,因为我似乎表明德国的比例低于澳大利亚的比例。

答案 4 :(得分:1)

    const indexes = [];
const decimalPercentages = [
  0,
  6.501707128047701,
  80.72721472499585,
  10.985525877598509,
  1.7855522693579489
];
const sum = decimalPercentages.map(d => d).reduce((a, b) => a + b, 0);
let percentages = decimalPercentages.map(d => Math.floor(d));
const percentagesTotal = percentages.reduce((a, b) => a + b, 0);

 Use the largest Remainder Method to get percentages total at 100
 inspired by https://stackoverflow.com/a/13485888/9477129
 This code implements the Largest Remainder method

if (100 - percentagesTotal) {
  const decimalValues = decimalPercentages.map((d) => {
    if (!d.toString().split('.')[1]) {
      return 0;
    }
    return d.toString().split('.')[1];
  });
  const targetIndexes = [...decimalValues].sort().splice(percentages.length -
    (100 - percentagesTotal));
  targetIndexes.forEach((element) => {
    indexes.push(decimalValues.indexOf(element));
  });
  percentages = percentages.map((element, key) => {
    if (indexes.includes(key)) {
      return element + 1;
    }
    return element;
  });
}