【问题标题】:Does modulus overflow?模数是否溢出?
【发布时间】:2013-10-10 00:38:37
【问题描述】:

我知道 (INT_MIN / -1) 会溢出,但 (INT_MIN % -1) 不会。至少这是在两个编译器中发生的情况,一个是 pre-c++11 (VC++ 2010),另一个是 post-c++11 GCC 4.8.1

int x = INT_MIN;
cout << x / -1 << endl; 
cout << x % -1 << endl;

给予:

-2147483648
0

这个行为标准是定义的还是实现定义的? 还有其他情况会导致除法运算溢出吗? 是否存在模运算符会溢出的情况?

【问题讨论】:

    标签: c++ visual-c++ c++11 integer-overflow


    【解决方案1】:

    根据CERT C++ Secure Coding Standard 模数可以can overflow 它说:

    [...]当被除数等于有符号整数类型的最小(负)值且除数等于 -1 时,可能会在模运算期间发生溢出。

    他们建议采用以下检查方式来防止溢出:

    signed long sl1, sl2, result;
    
    /* Initialize sl1 and sl2 */
    
    if ( (sl2 == 0 ) || ( (sl1 == LONG_MIN) && (sl2 == -1) ) ) {
      /* handle error condition */
    }
    else {
      result = sl1 % sl2;
    }
    

    C++ draft standard 部分 5.6 乘法运算符 段落 4 说(强调我的):

    二元 / 运算符产生商,二元 % 运算符产生第一个表达式除以第二个表达式的余数。如果 / 或 % 的第二个操作数为零,则行为未定义。对于整数操作数, / 运算符产生代数商,其中任何小数部分被丢弃;81如果商 a/b 可以用结果类型表示,则 (a/b)*b + a%b 等于 a;否则,a/b 和 a%b 的行为都是未定义的。

    C version of the CERT document 更深入地了解了% 在某些平台上的工作原理,在某些情况下INT_MIN % -1 可能会产生浮点异常

    preventing overflow for / 的逻辑与上述% 的逻辑相同。

    【讨论】:

    • 他们是否将“否则”部分添加到下一个标准中?当前的 C++11 标准不包括它 (open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf)。
    • @ZacHowland 看起来 otherwise 部分是从N3485 开始添加的,所有的前锋草案都使用相同的语言。这个previous thread 有一个很好的草稿链接集合。
    • @Pacerier 似乎他们已经移动了内容,所以在此过程中可能不可用。我修复了链接。
    【解决方案2】:

    不是模运算导致溢出:

    int x = INT_MIN;
    int a = x / -1; // int's are 2's complement, so this is effectively -INT_MIN which overflows
    int b = x % -1; // there is never a non-0 result for a anything +/- 1 as there is no remainder
    

    【讨论】:

      【解决方案3】:

      C++ 语言的每个现代实现都使用二进制补码作为整数的基本表示方案。因此,-INT_MIN 永远不能表示为 int。 (INT_MAX 为 -1+INT_MIN)。存在溢出,因为当 x 为 INT_MIN 时,值 x/-1 不能表示为 int。

      想想 % 计算什么。如果结果可以用 int 表示,就不会溢出。

      【讨论】:

      • (OP 在 C++ 中询问,而不是 C)
      • 谢谢,丹尼斯。原因是一样的,所以我编辑说C++。
      • 这应该类似于“每个现代主流实现”。当然,对于特殊或利基系统,存在一些奇怪的实现。任何人都可以查看 GCC 源代码,修改行为以使其不同但仍然符合(就 GCC 开始而言),并如实声称他们有一个与您的断言不同的 C 实现。
      • 是的。更好的是,我可能会说观察到的溢出行为表明“您的 C++ 实现与所有主流实现一样,使用二进制补码......”
      猜你喜欢
      • 1970-01-01
      • 2023-04-08
      • 1970-01-01
      • 1970-01-01
      • 2012-02-04
      • 2021-12-02
      • 1970-01-01
      • 2019-01-23
      • 1970-01-01
      相关资源
      最近更新 更多