Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/340.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 阶乘溢出引起的组合问题_Java_C#_Math - Fatal编程技术网

Java 阶乘溢出引起的组合问题

Java 阶乘溢出引起的组合问题,java,c#,math,Java,C#,Math,我需要一个函数,可以计算的(n,k)的纸牌游戏 我当前的尝试是使用基于常用阶乘方法的函数: static long Factorial(long n) { return n < 2 ? 1 : n * Factorial(n - 1); } static long Combinatory(long n , long k ) { return Factorial(n) / (Factorial(k) * Factor

我需要一个函数,可以计算的(n,k)的纸牌游戏

我当前的尝试是使用基于常用阶乘方法的函数:

    static long Factorial(long n)
    {
        return n < 2 ? 1 : n * Factorial(n - 1); 
    }

    static long Combinatory(long n , long k )
    {
        return Factorial(n) / (Factorial(k) * Factorial(n - k)); 
    }
我知道这是因为当我做阶乘(52)时,我溢出了long,但是我需要的范围结果并不像看起来那么大


有没有办法克服这个问题

而不是使用默认的组合公式
n!/(k!x(n-k)!)
,使用组合函数的递归属性

    (n, k) = (n - 1, k) + (n - 1, k - 1)
知道:
(n,0)=1
(n,n)=1

->这将使您避免使用阶乘和溢出您的long。

以下是您可以执行的实现示例:

 static long Combinatory(long n, long k)
    {
        if (k == 0 || n == k )
            return 1;

        return Combinatory(n - 1, k) + Combinatory(n - 1, k - 1); 
    }

编辑:使用更快的迭代算法

    static long Combinatory(long n, long k)
    {
        if (n - k < k)
            k = n - k;

        long res = 1;

        for (int i = 1; i <= k; ++i)
        {
            res = (res * (n - i + 1)) / i;
        }

        return res;
    } 
静态长组合(长n,长k)
{
if(n-k
e、 g:

静态长组合(长n,长k)
{
返回(长)(阶乘(新的biginger(n))/(阶乘(新的biginger(k))*阶乘(新的biginger(n-k)));
}
静态BigInteger阶乘(BigInteger n)
{
返回n<2?1:n*阶乘(n-1);
}

您需要添加对
System.Numerics
的引用才能使用BigInteger。

如果这不是家庭作业,Apache的commons math包中有一个高效的实现

如果是家庭作业,开始在实现中避免阶乘

使用(n,k)=(n,n-k)的属性使用k的最大值重写选择

然后请注意,您可以将n!/k!(n-k)!减少到n*n-1*n-2..*k/(n-k)*(n-k-1)..*1表示将[k,n]中的每个数字相乘,然后除以[1,n-k]中的每个数字

// From memory, please verify correctness independently before trusting its use.
//
public long choose(n, k) {
  long kPrime = Math.max(k, n-k);
  long returnValue = 1;
  for(i = kPrime; i <= n; i++) {
    returnValue *= i;
  }
  for(i = 2; i <= n - kPrime; i++) {
    returnValue /= i;
  }
  return returnValue;
}
//从内存中,请在信任其使用之前独立验证其正确性。
//
公共长选择(n,k){
长kPrime=数学最大值(k,n-k);
长返回值=1;

对于(i=kPrime;i递归公式也被称为,在我看来,这是计算组合数最简单的方法(对于0,你想计算二进制数。你为什么要用C#和Java来标记它?@p.s.w.g:因为这两种代码都是用Java和C#编译的,而且long都是64位的。我很好奇为什么你需要计算这么大的数字。近似值就足够了吗?这是非常低效的,而且他所说的数字,他可能仍然是他无法实际计算所需的值。这就像教科书上关于如何不使用递归的示例。@Servy,也是关于何时使用记忆的教科书示例。他还可以利用标识(n,k)=(n,n-k)是的,因为4!仍然不是一个很大的数字,但是当你到达8左右时,你就需要很长的时间,如果你能等很长一段时间,只需要几分钟。这就是O(N!)的问题所在算法。@jameslarge是的,这是一种可能的方法,可以使它不会执行得很糟糕。@Servy:我对答案进行了编辑。我希望它能让您满意,因为您的答案Java有一个BigInteger类,但它没有运算符重载,所以您需要调整
/

static long Combinatory(long n, long k)
{
    return (long)(Factorial(new BigInteger(n)) / (Factorial(new BigInteger(k)) * Factorial(new BigInteger(n - k))));
}

static BigInteger Factorial(BigInteger n)
{
    return n < 2 ? 1 : n * Factorial(n - 1);
}
// From memory, please verify correctness independently before trusting its use.
//
public long choose(n, k) {
  long kPrime = Math.max(k, n-k);
  long returnValue = 1;
  for(i = kPrime; i <= n; i++) {
    returnValue *= i;
  }
  for(i = 2; i <= n - kPrime; i++) {
    returnValue /= i;
  }
  return returnValue;
}
static  int64_t*    pascals_triangle( int N)
{
int n,k;
int64_t*    C = calloc( N+1, sizeof *C);
    for( n=0; n<=N; ++n)
    {   C[n] = 1;
        for( k=n-1; k>0; --k)
        {   C[k] += C[k-1];
        }
    }
    return C;
}