数学舍入问题总数> 100%

时间:2012-02-09 20:51:54

标签: c# math rounding

我有3个值全部四舍五入到没有小数位(即5%,25%,70%),除了我的70%真的是70.6%所以它达到71%,这使得我的总数为5%,25%, 71%= 101%,这是不好的,特别是因为我有一个条形图,如果它超过100%宽度,真的搞砸了。

如何确保我的3个值永远不会超过100%? 现在我使用Math.Round(值,0)是否有任何开关/选项可以用来保持我的3个值的总和超过100%?

由于

8 个答案:

答案 0 :(得分:11)

如果三个值总是必须总和为100,那么只对两个值进行舍入,并用

计算第三个值
third = 100 - Math.Round(a) - Math.Round(b);

注意:您的结果也可能太小。如果您有三个值为33.333333,则舍入并添加它们将产生99!


编辑(回应@ BlueRajaDannyPflughoeft的评论)

如果您有许多值,则所有舍入错误的总和可能会变大。因此,将它转移到最后一个值不是一个好主意。对于这些情况,我建议连续四舍五入。

double[] values = new double[] { 17.2, 3.7, 4.6, 5.8 };
int[] percent = new int[values.Length];

double sum = values.Sum();
int totalPercent = 100;
for (int i = 0; i < values.Length; i++) {
    double rawPercent = sum == 0 ? 0 : values[i] / sum * totalPercent;
    sum -= values[i];
    int roundedPercent = (int)Math.Round(rawPercent);
    totalPercent -= roundedPercent;
    percent[i] = roundedPercent;
}
// values         =  { 17.2,   3.7,    4.6,    5.8 }
//
// Percents:
// percent        => { 55,     12,     15,     18 }
// raw (exact)    => { 54.952, 11.821, 14.696, 18.530 }   (rounded to 3 decimals)
// raw continuous => { 54.952, 11.809, 14.596, 18.000 }

它并不完美,但错误不应超过1%。这是另一个例子

values         =  { 10.0,   10.0,   10.0,   10.0,   10.0,   10.0 }

Percents:
rounded        => { 17,     17,     16,     17,     16,     17 }
raw (exact)    => { 16.667, 16.667, 16.667, 16.667, 16.667, 16.667 }   
raw continuous => { 16.667, 16.600, 16.500, 16.667, 16.500  17.000 }

答案 1 :(得分:5)

不要添加舍入值并期望得到任何有意义的东西。添加未包含的值。如果那不符合你的要求,你必须通过添加舍入值来解释你认为你正在完成的事情。

答案 2 :(得分:2)

如果你不在乎这些值总和小于 100,那么简单的解决方案就是在整个过程中使用Math.Floor

如果你想要向上/向下舍入并且结果正好为100,那就更有趣了。这是一种方法 - 将它们全部向下舍入,然后选择性地将它们向上舍入到最大分数第一,直到再次达到100:< / p>

public static void RoundTo100Percent(IList<double> list)
{
    // get the sort order before changing any items
    IList<int> sortOrder = list.Select((n, i) => new { Key = n - Math.Truncate(n), Index = i }).OrderByDescending(ki => ki.Key).Select(ki => ki.Index).ToList();

    // round them all down to start with
    for (int i = 0; i < list.Count; i++)
    {
        list[i] = Math.Floor(list[i]);
    }

    // then round them up selectively, starting with those with the highest fractional part
    // e.g. 5.9 will round up to 6.0 before 7.8 rounds up to 8.0.
    int numberOfItemsToRoundUp = 100 - (int)list.Sum();
    foreach (int sortIndex in sortOrder.Take(numberOfItemsToRoundUp))
    {
        list[sortIndex]++;
    }
}

答案 3 :(得分:1)

你不能像这样在最后做检查:

if (total > 100)
  total = 100;

答案 4 :(得分:1)

好吧,如果你不圆,那么他们都会加起来达到100%。使用浮点数/双打/小数。问题解决了。

毕竟,为什么你要降低你的准确度? - 顺便说一句,这就是舍入。

答案 5 :(得分:0)

最好将所有帐户四舍五入,然后将剩余余额作为“统计四舍五入”或类似内容。

答案 6 :(得分:0)

为什么不将所有3个值加在一起,然后围绕最终结果? 33.3 + 33.3 + 33.3 = 99.9然后舍入到100,单独舍入只会出现在99,因为每个都会向下舍入。

答案 7 :(得分:0)

当我不得不将数据导入到一个系统中时,这个问题就出现了,这个系统要求每个用户的行集合的整数百分比都要加到100个。

重要的是要意识到没有正确的&#39;这样做的方式。例如,给定三个值,每个等于1/3,舍入总数等于99,应该加1哪个值以强制总数为100?没有正确的答案。只需选一个。

这是我在PHP中的解决方案:

function ensureColumnAddsToOneHundred(&$rows, $columnIndex)
{
   $percentagesTotalError = getColumnTotal($rows, $columnIndex) - 100;

   if ($percentagesTotalError > count($rows))
   {
      throw new Exception('Percentages total rounding error larger than nValues!');
   }

   // Add or subtract one from as many rows as is
   // necessary to ensure that the total is exactly 100.
   for ($i = 0; $i < abs($percentagesTotalError); ++$i)
   {
      $rows[$i][$columnIndex] += ($percentagesTotalError > 0)? -1: 1;
   }

   if (getColumnTotal($rows, $columnIndex) != 100)
   {
      throw new Exception('Percentages total not equal to 100 even after corrections!');
   }
}