【问题标题】:Catching an Integer Overflow in a recursive function [C]在递归函数中捕获整数溢出 [C]
【发布时间】:2012-03-14 07:59:32
【问题描述】:

更新:

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

#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;

下面的其中一个 cmets 建议 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)

【问题讨论】:

    标签: c recursion integer overflow


    【解决方案1】:

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

    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 这样的整数标志(如下所示),因为这是递归的,它将继续求和,因为 -1 是一个数字。
    【解决方案2】:

    一些建议:

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

    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;
    }
    

    【讨论】:

      【解决方案3】:

      执行以下操作:

      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;
      

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

      编辑:如果您不想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;
      

      【讨论】:

      • 其他递归调用也应该有一个类型转换。 (long) binom(n-1,k)
      • 这里假设sizeof(long) &gt; sizeof(int),不保证是真的。
      • @FredLarson 你是对的。补充说明。 @noMad,longint 的总和是 long
      • @asaelr 不一定有更广泛的原生类型可用(想想intlong 都是64 位的系统)。
      • @therefromhere 我没想到...希望现在我是对的 :)
      猜你喜欢
      • 2010-12-07
      • 2012-07-26
      • 2011-11-19
      • 1970-01-01
      • 1970-01-01
      • 2015-01-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多