找到要舍入的集合中的最大数字,然后将其四舍五入

Jam*_*iec 5 linq ienumerable rounding c#-3.0

正如标题所描述的那样,我有一组对象 - 称为Allocations - 包含描述和数字.集合中的所有数字加起来都是100%,但出于显示目的,我有时会达到整数百分比.在某些边缘情况下,对数字进行舍入后,最终得出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!)
Run Code Online (Sandbox Code Playgroud)

所要求的解决方案虽然不完善但会做到,但要找到最高的解决方案,然后将其四舍五入.在上面的示例中,四舍五入时1.42%将变为2%.编辑:通过"最高的一个向下舍入"我的意思是最圆的一个.因此1.42%下调0.42而65.23仅下跌0.23

所以现在代码,我有一个类

public class Allocation
{
  public string Description {get;set;}
  public doubel Percentage {get;set;}
}
Run Code Online (Sandbox Code Playgroud)

这些都是在一个IEnumerable<Allocation>.因此,可能使用LINQ,我如何确定哪一个是圆形的.或者更具体地说,如何生成IEnumerable<Allocation>带有舍入数字的新数据.

如果有人有任何其他建议,总是将圆整百分比总是等于100%甚至会更好!

Amy*_*y B 3

正如 ho1 所指出的,将 1 添加到特定行的解决方案并不能解决真正的问题。

考虑以下场景:

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
Run Code Online (Sandbox Code Playgroud)

这里有一些未经测试的代码,可能会让您接近您需要去的地方。这里可能有一个符号错误,所以要小心。

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();
Run Code Online (Sandbox Code Playgroud)

注意:按引入的错误排序可能会导致平局。考虑 3 项的情况,只有一项会获得 +1...您可能期望该项会被一致选择。如果多次运行的结果一致,则应打破平局。