Java:表达式包括二项式系数计算

时间:2017-10-23 10:33:50

标签: java math binomial-coefficients

任务是计算输入的自然数的表达式。

enter image description here

我知道我应该在这里计算二项式系数吗? enter image description here

我也知道(-1)^ p确定此数组是递减还是递增,但不知道如何在我的代码中使用p 我不太清楚如何将它们放在一起,这是我到目前为止所提出的并且它没有什么特别之处,因为我仍然无法理解如何在程序中编写它。

public static int calculateExpression(int n, int k,int p) {

      if(k<0 || n<k)
         {
             return 0;
         }
    // Find factorial of n

    int n_fac = 1;
        for (int j = 1; j <= n; j++) {
            n_fac = n_fac * j;

        }

    // Find factorial of k

    int k_fac = 1;
        for(int i = 1; i<=k; i++) {
            k_fac = k_fac * i;

        }

        // Find n-k fac
        int n_k = n-k;
        int n_k_fac = 1;
            for(int l = 1; l<=n_k;l++) {
                n_k_fac*=l;
            }

        //      n/k = n!/k!(n-k)!

        double resultOf_n_kDivision = n_fac/k_fac*n_k_fa;

    System.out.println(resultOf_n_kDivision);
    return n_k_fac;



}

4 个答案:

答案 0 :(得分:1)

阶乘函数是一个非常快速增长的函数,因此分别计算分子和分母可能不是一个好主意,因为即使相对较小的n值也可能导致溢出。

让我们看一下用于计算系数的迭代方法:

enter image description here

如果我们知道当前的那个,我们就可以计算出该行的下一个系数。因此,我们可以逐步计算S中的每个术语,同时不太关心溢出问题。

static int calculateExpression(int n, int k, int p)
{
   // first term of the row is (n, 0) = 1
   int binom = 1;

   // Iteratively find (n, k)
   for (int i = 0; i < k; i++)
      binom = (binom * (n - i)) / (i + 1);

   // sum the series
   int S = binom;
   for (int i = 0; i < p; i++) {
      // "trick": multiply with a minus sign each time to flip the sign
      binom = (-binom * (n - k - i)) / (k + i + 1);
      S += binom;
   }

   return S;
}

更新:并行数值测试:

n   k   p | orig  new
----------------------
5   3   2 | 6     6
10  4   1 | -42   -42
12  3   7 | 44    44
15  8   6 | 3433  8     // integer overflow occurred with the original method

正如您所看到的那样,两个函数在n = 15的最后一行之前是一致的,因为15! = 1307674368000比大多数Java实现中的int的最大正值大得多(32位)。

答案 1 :(得分:0)

使用抽象来更好地解决问题;定义facover。 然后问题变成:

public static int calculateExpression(int n, int k,int p) {
    int sum = 0;
    int minus1toP = 1;
    for (int i = 0; i <= p; i++) {
        sum += minus1toP * over(n, ...);
        minus1toP = -minus1toP;
    }
    return sum;
}

static int over(int n, int k) {
    return fac(n) / fac(k) / fac(n - k);
}

static int fac(int n) {
    int f = 1;
    for(int i = 2; i <= n; i++) {
        f *= i;
    }
    return f;
}

我没有提供整个解决方案(...),但可能已经太多了。

答案 2 :(得分:0)

我没有真正得到你的问题,但你可以使用它。

    public static double combination(int n, int k)
    {
        double nFactorial = getFactorialFromNToK(n, k);
        double kFactorial = getFactorialFromNToK(k, 1);

        return nFactorial / kFactorial;
    }

    public static double getFactorialFromNToK(double n, double k)
    {
        double factorial = 1;

        for (; n - k + 1 > 0; n--)
        {
            factorial *= n;
        }

        return factorial;
    }

这是对二项式扩展中项的系数的nCk的评估。

如果nCn是扩展中的一个术语,那么它会收敛,如果它在扩展中不作为术语存在,那么它就不会收敛。因此,如果它是一个自然数字扩展,那么它将始终收敛。

答案 3 :(得分:0)

更好的解决方案是使用lngamma函数而不是阶乘。这是计算因子的更有效方法。自然日志意味着划分大数字不会有问题。