在要四舍五入的集合中找到最高的数字,然后将其四舍五入 [英] Find the highest number in a set to be rounded down, and round it up instead
问题描述
正如标题所述,我有一组对象-称为分配-其中包含描述&一个号码.集合中的所有数字加起来等于100%,但是出于显示目的,我有时会舍入为一个整数.在某些情况下,四舍五入后我得到了99%.
As the title describes, I have a set of objects - call them Allocations - which contain a description & a number. All numbers in the set add up to 100%, but for display purpose I sometimes round to a whole percent. In some edge cases, having rounded the numbers I end up with 99%.
示例:
Description | Actual | Rounded
===============================
Allocation A | 65.23% | 65%
Allocation B | 25.40% | 25%
Allocation C | 7.95% | 8%
Allocation D | 1.42% | 1%
===============================
Total | 100% | 99% (Bad!)
所请求的解决方案虽然不完美,但是可以解决,它是找到要四舍五入的最高解决方案,然后将其向上舍入.在上面的示例中,四舍五入后的1.42%将变为2%. 将要舍入的最高位"是指被舍入到最远的位.因此,将1.42%向下舍入为0.42,而65.23仅向下舍入为0.23
The requested solution, which is imperfect but will do, is to find the highest one to be rounded down, and round it up instead. In the example above, 1.42% would become 2% when rounded. By "Highest one to be rounded down" I mean the one which is being rounded the furthest. Hence 1.42% is being rounded down by 0.42 whereas the 65.23 is only being rounded down 0.23
所以现在代码,我有一个课
So now the code, I have a class
public class Allocation
{
public string Description {get;set;}
public doubel Percentage {get;set;}
}
这些被保存在IEnumerable<Allocation>
中.因此,潜在地使用LINQ,我如何确定哪一个是要四舍五入的.更具体地说,如何生成带有四舍五入数字的新IEnumerable<Allocation>
.
And these are held in an IEnumerable<Allocation>
. So, potentially using LINQ, how can I determine which one is the one to round up. Or more specifically, how can I generate a new IEnumerable<Allocation>
with the numbers rounded.
如果有人有其他建议总是将舍入百分比始终等于100%,那就更好了!
If anyone has any other suggestion for always making rounded percentage always equate to 100% that would be even better!
推荐答案
正如ho1所指出的,将1加到特定行的解决方案并不能解决真正的问题.
As ho1 has indicated, the solution to add 1 to a specific row doesn't solve the real problem.
请考虑以下情形:
3 items evenly divided, 100/3 = 33 ; 33 * 3 = 99 ; Error = -1
7 items evenly divided, 100/7 = 14 ; 14 * 7 = 98 ; Error = -2
66 items evenly divided, 100/66 = 2 ; 2 * 66 = 132 ; Error = 32
这里有一些未经测试的代码,可能会使您接近需要去的地方.此处可能有符号错误,请当心.
Here's some untested code that might get you close to where you need to go. There's probably a sign error in here so watch out.
public class AllocationRoundingWrapper
{
public Allocation Original {get;set;}
public double Rounded {get;set;}
public double IntroducedError()
{
return Rounded - Original.Percentage;
}
}
//project the Allocations into Wrappers for rounding efforts.
List<Allocation> source = GetAllocations();
List<AllocationRoundingWrapper> roundingWrappers = source
.Select(a => new AllocationRoundingWrapper()
{
Original = a,
Rounded = Math.Round(a.Percentage)
}).ToList();
int error = (int) roundingWrappers.Sum(x => x.IntroducedError());
//distribute the rounding errors across the
// items with the absolute largest error.
List<RoundingWrapper> orderedItems = error > 0 ?
roundingWrappers.OrderByDescending(x => x.IntroducedError()).ToList() :
roundingWrappers.OrderBy(x => x.IntroducedError()).ToList();
IEnumerator<RoundingWrapper> enumerator = orderedItems.GetEnumerator();
while(error > 0)
{
enumerator.MoveNext();
enumerator.Current.Rounded += 1.0;
error -= 1;
}
while(error < 0)
{
enumerator.MoveNext();
enumerator.Current.Rounded -= 1.0;
error += 1;
}
//project back into Allocations for the result
List<Allocation> result = roundingWrappers
.Select(x => new Allocation()
{
Description = x.Original.Description,
Percentage = x.Rounded
}).ToList();
注意:按引入的错误进行订购可能会导致并列.考虑3个项目的情况,只有一个项目会获得+1 ...您可能希望该项目被一致选择.如果期望从多次运行中获得一致的结果,则应打破联系.
Note: Ordering by introduced error can result in ties. Consider the 3 items case, only one item will get +1... you may expect that item to be consistently chosen. If consistent results are expected from multiple runs, ties should be broken.
这篇关于在要四舍五入的集合中找到最高的数字,然后将其四舍五入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!