假设我们有一个带整数的项目列表:
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,对软件用户来说看起来有点奇怪。你会如何解决这个问题?
答案 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)
如果你担心结果对用户来说有点奇怪,我会在结果上加上一个脚注,提到百分比已经四舍五入,而我的总数不是100%。只有在舍入导致此行为时,您才能以编程方式显示消息。
USA percentage: 43
Australia percentage: 29
Germany percentage: 29
*Percentages may not total 100 due to rounding
由于您使用的是Ruby,我建议使用rational个数字。这样您就不会在需要时失去精度。您可以使用旁边的有理数字显示百分比,而不是脚注,如下所示:
USA percentage: 43 (3/7)
Australia percentage: 29 (2/7)
Germany percentage: 29 (2/7)
包含更多小数位,以便舍入误差不那么严重:
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;
});
}