在递归函数中捕获整数溢出[C]

时间:2012-02-23 20:52:07

标签: c recursion integer overflow

更新:

感谢您提供有用的意见和建议。用你们所说的,这就是我想出的:

#include <limits.h>
  ...
  else {
     int a = binom(n - 1, k - 1);
     int b = binom(n - 1, k);
     if(a > 0) {
         if (b > INT_MAX - a) {          // case 1: integer overflow
             printf("int overflow\n");
             return;
         }
     }
     else if (b < INT_MIN - a) {         // case 2: integer overflow
         printf("int overflow\n");
         return;
     }
     int c = a + b;
     return c;
}

我还有另外一个问题。在上面的代码中,当我捕获整数溢出时,我没有返回值 - 它只是return;

下面的一条评论建议return -1;,但考虑到-1仍然是一个有效的整数,这是行不通的,对吗?

我不知道该怎么做,因为我的函数的返回类型是intreturn;是否有效或有更好的方法吗?还建议使用exit(1);,但这会退出整个程序还是只退出函数?


原文:

你的函数应该使用整数运算来确保结果是准确的 还可以检测因超出允许的最大值而导致的任何整数溢出。

我试图在计算二项式系数时捕获整数溢出。虽然这是一个简单的概念,但让我失望的是,这不仅仅是一次性的补充,而是一种不断执行求和的递归算法。

这是功能:

// recursive function to calculate binomial coefficients
int binom(int n, int k){
    if(k == 0){         // base case
         return 1;
    }
    else if (n == 0){
         return 0;
    }
    else{
         return binom(n - 1, k - 1) + binom(n - 1, k);  // recursive call

    }
}

根据该逻辑,我假设catch应该在递归调用语句中。类似的东西:

if(binom(n-1, k-1) + binom(n-1,k)) causes overflow, return error, else proceed with binom(n-1, k-1) + binom(n-1,k)

3 个答案:

答案 0 :(得分:3)

有符号溢出是未定义的行为,您必须在溢出发生之前检查溢出。

int a, b;
int c;

...

/* Compute a + b and store the result in c */

if (a > 0) {
    if (b > INT_MAX - a) {
        // a + b overflows (i.e., would be > INT_MAX)
    }
} else if (b < INT_MIN - a) {
        // a + b overflows (i.e., would be < INT_MIN)
}

c = a + b;

所以对于递归函数:

a = binom(n - 1, k - 1);
b = binom(n - 1, k);

// if no overflow
c = a + b;

return c;

在您的示例中,您还必须检查nk不是== INT_MIN,否则- 1操作也会溢出。

答案 1 :(得分:0)

做类似的事情:

long res=(long)binom(n - 1, k - 1) + binom(n - 1, k);
if (res>INT_MAX) {
 printf("int overflow\n");
 exit(1);
}
return (int)res;

(假设long比系统中的int长。如果不是,请使用更宽的类型)

编辑:如果您不希望exit出错,则应确定一个值(例如-1)来表示错误。此外,使用unsigned代替long更好(和更正):

int a=binom(n - 1, k - 1),b=binom(n - 1, k);
if (a<0 || b<0 || (unsigned)a+(unsigned)b>INT_MAX) return -1;
return a+b;

答案 2 :(得分:0)

一些建议:

1)您使用的是有符号整数;如果你正在使用严格正数,你应该使用unsigned int或unsigned long long。对于带符号的int,当发生算术溢出时,它将溢出到可能的最大负数

2)编译器将沿INT_MAX的行定义一个预处理器符号;你可以很好地利用它,例如:

#inlcude <stdtypes.h>

uint32_t binom( uint32_t n, uint32_t k ){
  // (...)
  } else {
    int32_t   A = binom( n-1, k-1 )
            , B = binom( n-1, k );
    if( (double)A + (double)B > INT_MAX ){
      // error condition
    } else {
      retval = A+B;
    }
  }

  return retval;
}