简体   繁体   English

计算可能的组合数 - C#

[英]Calculating the number of possible combinations - C#

I'm trying to calculate the number of possible combinations so I'm using some maths here (to be precise factorials). 我正在尝试计算可能组合的数量,所以我在这里使用一些数学(精确的阶乘)。 For example, if I have 50 numbers and I want to organize them into groups of 5, how many groups (combinations) are possible to make. 例如,如果我有50个数字并且我想将它们组织成5个组,那么可以制作多少组(组合)。 I'm using this formula: allNumbers! / (allNumbers - PerGroup)! 我正在使用这个公式: allNumbers! / (allNumbers - PerGroup)! allNumbers! / (allNumbers - PerGroup)! , but it comes up with an error for this particular example. ,但它为这个特定的例子提出了一个错误。 It says that dividing by zero is forbidden. 它说禁止除以零。 How can I manage this to work? 如何管理这项工作? This is my code: 这是我的代码:

int b = 1;
int n = 1;

if (allNumbers - PerGroup == 0)
{
      return 1;
}
else if (allNumbers - PerGroup == 1)
{
      return allNumbers;
}
else
{
      for (int i = 1; i <= allNumbers; i++)     
      {
             b *= i;
      }

      for (int i = 1; i <= allNumbers - PerGroup; i++)
      {
             n *= i;
      }

      if (Enumerable.Range(1,int.MaxValue).Contains(b/n)) //line with ERROR!
      {
             return b/n;
      }
      else
      {
             return int.MaxValue;
      }
}

Enumerable.Range(1,int.MaxValue).Contains(b/n) check doesn't check if the value is valid, because b/n is already computed and stored as int by this time. Enumerable.Range(1,int.MaxValue).Contains(b/n) check不检查该值是否有效,因为b / n已经计算并且此时存储为int。

You get division by zero because variable n is overflowed and becomes zero. 由于变量n溢出并变为零,因此除以零。 In the following code you can see how overflow occurs. 在以下代码中,您可以看到溢出是如何发生的。

using System;

public class Test
{
    public static void Main()
    {
        int n = 1;
        for (int i = 1; i <= 50; i++) {
            n *= i;
            Console.WriteLine("i = {0}, n = {1}", i, n);
        }
    }
}

Output: 输出:

i = 1, n = 1
i = 2, n = 2
i = 3, n = 6
i = 4, n = 24
i = 5, n = 120
i = 6, n = 720
i = 7, n = 5040
i = 8, n = 40320
i = 9, n = 362880
i = 10, n = 3628800
i = 11, n = 39916800
i = 12, n = 479001600
i = 13, n = 1932053504
i = 14, n = 1278945280
i = 15, n = 2004310016
i = 16, n = 2004189184
i = 17, n = -288522240
i = 18, n = -898433024
i = 19, n = 109641728
i = 20, n = -2102132736
i = 21, n = -1195114496
i = 22, n = -522715136
i = 23, n = 862453760
i = 24, n = -775946240
i = 25, n = 2076180480
i = 26, n = -1853882368
i = 27, n = 1484783616
i = 28, n = -1375731712
i = 29, n = -1241513984
i = 30, n = 1409286144
i = 31, n = 738197504
i = 32, n = -2147483648
i = 33, n = -2147483648
i = 34, n = 0
i = 35, n = 0
i = 36, n = 0
i = 37, n = 0
i = 38, n = 0
i = 39, n = 0
i = 40, n = 0
i = 41, n = 0
i = 42, n = 0
i = 43, n = 0
i = 44, n = 0
i = 45, n = 0
i = 46, n = 0
i = 47, n = 0
i = 48, n = 0
i = 49, n = 0
i = 50, n = 0

since allNumbers! 既然allNumbers! always contains (allNumbers - PerGroup)! 总是包含(allNumbers - PerGroup)! , why don't you exclude them from start. ,你为什么不从头开始排除他们。

int b = 1;

if (allNumbers - PerGroup == 0)
{
      return 1;
}
else if (allNumbers - PerGroup == 1)
{
      return allNumbers;
}
else
{
      for (int i = (allNumbers - PerGroup + 1); i <= allNumbers; i++)     
      {
             b *= i;
      }

      return b;
}

I guess the error is OutOfMemoryException because you are creating a huge amount of unnecessary integers . 我猜错误是OutOfMemoryException,因为你正在创建大量不必要的integers ( Enumerable.Range(1,int.MaxValue) ) note that each int takes 4 bytes from your memory. Enumerable.Range(1,int.MaxValue) )注意每个int占用内存中的4个字节。

Im not sure what you are trying to do there but you can use double type so if the number becomes very large it will just give you PositiveInfinity . 我不知道你在那里尝试做什么,但你可以使用double类型,所以如果数字变得非常大,它只会给你PositiveInfinity

Or you can use checked to control integer overflow with try and catch. 或者您可以使用checked来控制try和catch的整数溢出。

Another way is to pre calculate the number when integer overflow happens. 另一种方法是在整数溢出发生时预先计算数字。 for example factorial of 14 will overflow for int and factorial of 22 will overflow for long . 例如,factorial of 14将溢出为int而factorial of 22将溢出long

Also you dont have to write for loop twice. 你也没有两次写for循环。 you can use method for this purpose. 你可以使用方法来达到这个目的。

You dont need to check for allNumbers - PerGroup == 0 to prevent zero division. 您不需要检查allNumbers - PerGroup == 0以防止零分割。 that wont happen because factorial of 0 is 1 and our factorial implementation returns 1 by its nature when the input is 0! 这不会发生,因为0的阶乘是1,当输入为0时,我们的阶乘实现按性质返回1! (because the for loop never iterates in that case and the counter starts from 1.) (因为for循环在这种情况下从不迭代,计数器从1开始。)

private static int Cominations(int allNumbers, int perGroup)
{
    if(allNumbers > 13)
    {
        Console.WriteLine("Too big number!");
        return -1;
    }

    return Factorial(allNumbers)/Factorial(allNumbers - perGroup);
}

private static int Factorial(int number)
{
    int n = 1;

    for (int i = 1; i < number; i++)
    {
        n *= i;
    }

    return n; // returns 1 when number is 0
}

If you want to calculate factorial of bigger numbers use BigInteger type from System.Numberics namespace. 如果要计算较大数字的阶乘,请使用System.Numberics命名空间中的BigInteger类型。

using System.Numerics;

//...

private static BigInteger Factorial(int number)
{
    BigInteger n = 1;

    for (int i = 1; i < number; i++)
    {
        n *= i;
    }

    return n;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM