说在前:
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
-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 可能发生溢出)