java大数溢出问题

说在前:

java没有任何无符号(unsigned)形式的int、long、short或byte类型。

补码表示的溢出问题

由于计算机中的数字用补码表示,例如8bit的byte类型的表示范围为:

[-128, 127]

0 = [0000 0000](补)

-128 = [1000 0000](补)

127 = [0111 1111](补)

当byte类型的变量超上限127时,如:

+128 = -(-128)= 127 + 1
= [0111 1111](补)+ [0000 0001](补)
= [1000 0000](补)
= -128

+129 = 127 + 2
= [0111 1111](补)+ [0000 0010](补)
= [1000 0001](补)
= [1111 1111](原)
= -127

当byte类型的变量超过下限-128时:

-129 = -128 - 1
= [1000 0000](补) +[1000 0001](补)
= [0000 0001](补)
= [0111 1111]
= 127

扫描二维码关注公众号,回复: 9195996 查看本文章

-130 = -128 - 2
= [1000 0000](补) + [1000 0010](补)
= [0000 0010](补)
= [0111 1110](原)
= 126
测试代码如下:

public static void main(String[] args) {
        byte a = -128; 
        byte b = (byte) 128;
        byte c = (byte) 129; 
        byte d = (byte) 130;
        byte e = (byte) -129, f = (byte) -130;
        System.out.println(a == ((byte)-a));    // true
        System.out.println(b);  // -128
        System.out.println(c);  // -127
        System.out.println(d);  // -126
        System.out.println(e);  // 127
        System.out.println(f);  // 126
    }

控制台输出如下:

"C:\Program Files\Java\jdk1.8.0_131\bin\java" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA ***" com.it18zhang.java.Test
true
-128
-127
-126
127
126

java中大数溢出问题

参考连接:https://blog.csdn.net/u011080472/article/details/51280919#大数溢出问题

int类型在32位系统中占4个字节、32bit,补码表示的的数据范围为:

[10000000 00000000 00000000 00000000] ~ [01111111 11111111 11111111 11111111]

[−231,231−1][−231,231−1]
[-2147483648, 2147483647]

在java中表示为:

[Integer.MIN_VALUE, Integer.MAX_VALUE]

与byte类型的表示一样,由于负数比正数多表示了一个数字。对下限取相反数后的数值会超过上限值,溢出到下限,因此下限的相反数与下限相等;对上限取相反数的数值为负值,该负值比下限的负值大1,在可以表示的范围内,因此上限的相反数是上限直接取负值。

// 2147483647   [01111111 11111111 11111111 11111111]
System.out.println(Integer.MAX_VALUE);      

// -2147483648  [10000000 00000000 00000000 00000000]
System.out.println(Integer.MIN_VALUE);

// -2147483647      正常
System.out.println(-Integer.MAX_VALUE);     

// -2147483648  2147483648,超过上限,发生溢出
System.out.println(-Integer.MIN_VALUE);     

// true,2147483648 发生溢出
// 对下限去相反数后的数值会超过上限值,溢出到下限,因此下限的相反数与下限相等
System.out.println((Integer.MIN_VALUE == -Integer.MIN_VALUE));  

这个特点在进行大数溢出判断时会用到,例如JKD源码中字符串转化为int类型的函数,Integer.parseInt(String str)中,只能使用对上限取反Integer.MAX_VALUE当成负数累减,而不能对下限取反Integer.MIN_VALUE当成正数累加。

public static int parseInt(String s) throws NumberFormatException {
        return parseInt(s,10);
    }
public static int parseInt(String s, int radix)
                throws NumberFormatException
    {
        /*
         * WARNING: This method may be invoked early during VM initialization
         * before IntegerCache is initialized. Care must be taken to not use
         * the valueOf method.
         */

        if (s == null) {
            throw new NumberFormatException("null");
        }

        if (radix < Character.MIN_RADIX) {
            throw new NumberFormatException("radix " + radix +
                                            " less than Character.MIN_RADIX");
        }

        if (radix > Character.MAX_RADIX) {
            throw new NumberFormatException("radix " + radix +
                                            " greater than Character.MAX_RADIX");
        }

        int result = 0;
        boolean negative = false;
        int i = 0, len = s.length();
        //边界值  -0x7fffffff
        int limit = -Integer.MAX_VALUE;
        //边界值右移一位
        int multmin;
        int digit;

        if (len > 0) {
            char firstChar = s.charAt(0);
            if (firstChar < '0') { // Possible leading "+" or "-"
                if (firstChar == '-') {
                    negative = true;
                    //边界值为0x80000000
                    limit = Integer.MIN_VALUE;
                } else if (firstChar != '+')
                    throw NumberFormatException.forInputString(s);

                if (len == 1) // Cannot have lone "+" or "-"
                    throw NumberFormatException.forInputString(s);
                i++;
            }
            //radix=10,limit / radix表示limit右移一位
            multmin = limit / radix;
            while (i < len) {
                // Accumulating negatively avoids surprises near MAX_VALUE
                //将字符转换成对应进制的整数
                digit = Character.digit(s.charAt(i++),radix);
                if (digit < 0) {
                    throw NumberFormatException.forInputString(s);
                }
                if (result < multmin) {
                    throw NumberFormatException.forInputString(s);
                }
                result *= radix;
                if (result < limit + digit) {
                    throw NumberFormatException.forInputString(s);
                }
                result -= digit;
            }
        } else {
            throw NumberFormatException.forInputString(s);
        }
        return negative ? result : -result;
    }

上述算法关键点:
1)边界值的运用。正数的边界值为1至0x7fffffff;负数的边界值为-1至0x80000000;
2)符号标记negative的使用,简化处理逻辑。代码中将所有数据当做负数(正数)来处理,最后处理符号问题;
3)巧妙的防止大数溢出。方法中multmin这个变量是为了在循环中result*=radix不会发生越界,使if (result < multmin)正常执行;if (result < limit + digit)的判断,result < limit + digit的比较防止了溢出发生(result - digit < limit 可能发生溢出)

发布了85 篇原创文章 · 获赞 40 · 访问量 23万+

猜你喜欢

转载自blog.csdn.net/ljb825802164/article/details/89787935
今日推荐