首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用C++中的置换(nPr,nCr)函数避免整数溢出

用C++中的置换(nPr,nCr)函数避免整数溢出
EN

Stack Overflow用户
提问于 2012-06-13 21:38:08
回答 5查看 4.9K关注 0票数 0

我正在尝试做一些与统计相关的函数,这样我就可以执行一些相关的过程(例如:概率的统计计算,生成任意深度的Pascal三角形,等等)。

我遇到了一个问题,我可能正在处理溢出。例如,如果我想计算(n=30,p=1)的nPr,我知道我可以将其简化为:

代码语言:javascript
复制
30P1 = 30! / (30 - 1)!
     = 30! / (29)!
     = 30! / 29!
     = 30

但是,当使用下面的函数进行计算时,由于整数溢出,我似乎总是会得到无效值。有没有不需要使用库就可以支持任意大数字的变通方法?我在其他关于gamma函数的文章中读了一点,但找不到具体的例子。

代码语言:javascript
复制
int factorial(int n) {
   return (n == 1 || n == 0) ? 1 : factorial(n - 1) * n;
}


int nCr(int n, int r) {
   return (nPr(n,r) / factorial(r));
   //return factorial(n) / factorial(r) / factorial(n-r));
}


int nPr(int n, int r) {
   return (factorial(n) / factorial(n-r));
}
EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2012-06-13 21:55:34

你看起来是在正确的轨道上,所以你开始吧:

代码语言:javascript
复制
#include <math.h>
#include <stdio.h>

int nCr(int n, int r) {
   if(r>n) {
      printf("FATAL ERROR"); return 0;
     }       
   if(n==0 || r==0 || n==r) {
      return 1;
   } else {
      return (int)lround( ((double)n/(double)(n-r)/(double)r) * exp(lgamma(n) - lgamma(n-r) - lgamma(r)));
   }
}


int nPr(int n, int r) {
   if(r>n) {printf("FATAL ERROR"; return 0;}
   if(n==0 || r==0) {
      return 1;
   } else {
      if (n==r) {
         r = n - 1;
      }
      return (int)lround( ((double)n/(double)(n-r)) * exp(lgamma(n) - lgamma(n-r)));
   }
}

要编译,请执行以下操作:gcc -lm myFile.c && ./a.out

请注意,结果的准确性受到double数据类型的位深度的限制。您应该能够获得良好的结果,但需要注意的是:将上面所有的int替换为long long unsigned并不一定能保证较大的n,r值的结果是准确的。在某些情况下,您仍然需要一些数学库来处理任意大的值,但这应该可以帮助您避免较小的输入值。

票数 0
EN

Stack Overflow用户

发布于 2012-12-16 13:31:10

这是一种不使用gamma函数进行计算的方法。它依赖于n_C_r = (n/r) * ((n-1)C(r-1))的事实,并且对于任何正值,n_C_0 =1,因此我们可以使用它来编写如下所示的递归函数

代码语言:javascript
复制
public long combination(long n, long r) {
    if(r==0)
        return 1;
    else {
        long num = n * combination(n - 1, r - 1);
        return num/r;
    }
}
票数 3
EN

Stack Overflow用户

发布于 2012-06-13 21:45:35

我想你有两个选择:

  1. 使用了一个大整型库。这样你就不会失去精度(浮点可能在某些情况下可以工作,但对你的函数来说是一个很差的substitute).
  2. Restructure,所以它们不会达到很高的中间值。例如,factorial(x)/factorial(y)是从y+1x的所有数字的乘积。所以只要写一个循环和乘法就行了。这样,只有当最终结果溢出时,才会出现溢出。
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11016069

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档