zoukankan      html  css  js  c++  java
  • 整数算术溢出问题的分析

        这篇对整数的一些基本运算产生的溢出问题进行分析。

      当你进行加减乘除运算的时候,如果这个数字很大,运算产生的结果就可能会出乎你最初设计程序的预料,这对程序来说是一种很可怕的漏洞,这让一些恶意的访问者对程序作出一些破坏性的事情,这样造成的危害可能是很大的。

    这里先定义一些宏定义作为返还值:

    #define OVERFLOW 1      //算术溢出(正溢出)
    #define NOT_OVERFLOW 0             //未溢出
    #define NEGATIVE_OVERFLOW -1      //负溢出

    当进行无符号整数加法计算的时候。

      无符号整数的范围是 0 ≤ x  UMax ,UMax = 2w - 1 (w是当前类型的位数) ,如果两个数相加的结果小于任何一个数,那么就可以判断算术溢出。判断的代码如下:

    int uadd_ok(unsigned x, unsigned y)
    {
        unsigned uadd=x+y;
        if( uadd < x || uadd < y)
            return OVERFLOW;
            
        return NOT_OVERFLOW;
    }

    当进行有符号整数加法计算的时候。

      有符号整数的范围是 TMin ≤ x ≤ TMax TMin = -2w-1 ,TMax = 2w-1 - 1 那么为什TMax的绝对之为什么会比TMin的绝对之小一,那么假设 w= 4 观察一下。因为有符号数的最高位是符号位,所以TMax的最高位就是 0 ,为了让数字更大那么其余就应该是 1 ,那么 TMax (4) = 0111 = 22+21+20=23-1=2w-1-1。有符号数的负数部分一般都是用补码表示的 TMin 最高位就需要是 1 因为只有最高位是代表负数,其余位都是正数,最后这个数的值是各个位的值的加和得到的,所以其余位都需要是 0 ,那么 TMin(4)=1000= -23 = -2w-1 。那么判断有符号数加法的代码一种错误如下,它利用了阿贝尔群得知补码加法的时候,(x+y)-y=y 在溢出的情况下是成立的。所以就有可能出现如下的代码:

    int tadd_ok(int x, int y)
    {
         int sum=x+y;
         return (sum - y == y) && (sum - x == y) ; 
    }    

    但是这个代码的返回值永远是 1, 因为在不溢出的情况下表达式成立是显而易见的。

    所以就需要考虑多方面的因素了,两个数都大于零的时候,如果结果是负数那么可判断溢出。如果两个数都是负数,结果为正数那么判断也溢出。

    代码如下:

    int tadd_ok(int x, int y)
    {
        int tadd=x+y;
        if( x > 0 && y > 0 )
            if( tadd < 0 )
                return OVERFLOW;
        
        if( x < 0 && y < 0 )
            if( tadd >= 0 )
                return NEGATIVE_OVERFLOW;
        
        return NOT_OVERFLOW;
    }

    当进行有符号减法运算的时候。

      这个时候你可能想像这样调用写好的 tadd_ok( x, -y );  函数,但是实际上在一些情况下这是错误的,因为 TMin = -TMin ,这样你想要的 -TMin 就没有变成 | TMin | 却变成了TMin 所以就需要增加一些判断。

    代码如下:

    int tsub_ok(int x, int y)
    {
        if( y != 0 && y == -y )
        {
            if( x >= 0 )
                return OVERFLOW;
            return NOT_OVERFLOW;
        }
        return tadd_ok(x,-y);
    }

    当是乘法运算的时候不论有符号还是无符号,溢出的部分都是直接截掉的。

      当然乘法是可以使用 ( x * y ) / x = y 进行判断的因为溢出的时候这是不成立的,当然你需要保证 x , y 不是零 ,如果是零作为除数是不合理的。

    所以可以写出如下代码:

    int tmult_ok(int x, int y)
    {
        int tmult=x*y;
        if( x != 0 && y!= 0 )
        {
            if( tmult / x == y )
                return NOT_OVERFLOW;
            return OVERFLOW;
        }
        return NOT_OVERFLOW;
    }

      

  • 相关阅读:
    Frequency of String CodeForces
    Sign on Fence CodeForces
    洛谷 P3332 [ZJOI2013]K大数查询 || bzoj3110
    spoj DYNALCA
    洛谷 P2824 [HEOI2016/TJOI2016]排序 (线段树合并)
    洛谷 P3203 [HNOI2010]弹飞绵羊 || bzoj2002
    bzoj 1036: [ZJOI2008]树的统计Count
    Shiro Authenticator认证器
    Shiro 十分钟教程
    Shiro 架构
  • 原文地址:https://www.cnblogs.com/foreverW/p/7512859.html
Copyright © 2011-2022 走看看