数学舍入问题合计>;100%

本文关键字:gt 100% 舍入 问题 | 更新日期: 2023-09-27 18:23:52

我有三个值,它们都被四舍五入到没有小数点的位置(即5%、25%、70%),除了我的70%实际上是70.6%,所以它变成了71%,这使得我的总数为5%、25%和71%=101%,这不好,尤其是因为我有一个条形图,如果它超过100%的宽度,就会变得非常糟糕。

如何确保我的3个值永远不会超过100%?现在我正在使用数学。Round(值,0)有什么开关/选项可以让我的3个值的总和不超过100%吗?

感谢

数学舍入问题合计>;100%

如果三个值的总和总是必须达到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 }

不要添加舍入值,希望得到任何有意义的值。将未舍入的值相加。如果这不能达到你想要的效果,你必须解释你认为通过添加四舍五入的值来实现的目标。

如果您不在乎这些值的总和可能小于100,那么简单的解决方案就是始终使用Math.Floor

如果你想向上/向下取整,结果正好是100,这会变得更有趣。这里有一种方法–将它们全部向下四舍五入,然后有选择地将它们向上四舍五舍五入——首先是最大分数,直到你再次达到100:

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]++;
    }
}

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

if (total > 100)
  total = 100;

好吧,如果你不四舍五入,那么它们加起来将达到100%。使用浮点/双精度/小数。问题解决了。

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

最好对所有账户进行四舍五入,然后将剩余余额作为"统计四舍五进"或类似的余额。

为什么不将所有3个值相加,然后对最终结果进行舍入?33.3+33.3+333.3=99.9,然后四舍五入到100,单独四舍五进只会在99处出现,因为每个都会向下取整。

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

重要的是要认识到,没有"正确"的方法可以做到这一点。例如,给定三个值,每个值都等于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!');
   }
}