二进制表示负数的问题
我们知道十进制数1的二进制码用int型表示就是0000 0000 0000 0000 0000 0000 0000 0001
二进制码实际上并不能表示负数, 因为二进制数最小就是0000 0000 0000 0000 0000 0000 0000 0000 , 所以只要有数字存在就是大于0的
但实际的计算机中, 负数的运算也是必要的, 那该怎么存储呢?
于是人们根据实际的计算逻辑 1 + (-1) = 0 可以推算出, 只需要让表示负数的二进制与对应的正数的二进制相加为0就可以了.
那么, 就拿1的二进制数 0000 0000 0000 0000 0000 0000 0000 0001 作为示例, 这个二进制数加谁为 0000 0000 0000 0000 0000 0000 0000 0000 呢
如图, 二者相加就会进一位(即溢出), 而其余的位都是0, 所以, -1应该用1111 1111 1111 1111 1111 1111 1111 1111表示, 这种表示形式就是补码表示.
原码与补码的转换规则
计算机中存储的二进制数, 一律都是补码的形式存储的. 人们规定二进制数的最高位代表正负(0正1负), 补码就是原数值取反, 再加1 (符号位不参与取反加一)
正数的补码与原码相同 (即正数的补码就是它本身)
比如, 十进制数2, 原码形式如下
0000 0000 0000 0000 0000 0000 0000 0010
取反 (符号位不参与)
0111 1111 1111 1111 1111 1111 1111 1101
再加1 (符号位不参与)
即取出符号位, 剩余7位 111 1111 1111 1111 1111 1111 1111 1101 加 1, 结果为 1000 0000 0000 0000 0000 0000 0000 0010 (最高位1溢出了), 所以就是 000 0000 0000 0000 0000 0000 0000 0010, 再加上符号位0, 就是0000 0000 0000 0000 0000 0000 0000 0010, 还是原码本身.
负数的补码
比如, 十进制数-2, 原码形式如下 (与正2只是符号位不同)
1000 0000 0000 0000 0000 0000 0000 0010
取反 (符号位不参与)
1111 1111 1111 1111 1111 1111 1111 1101
再加1 (符号位不参与)
取出符号位, 剩余7位 111 1111 1111 1111 1111 1111 1111 1101 加 1, 结果为 111 1111 1111 1111 1111 1111 1111 1110 , 再加上符号位1, 就是1111 1111 1111 1111 1111 1111 1111 1110
Java实例
class Demo{
public static void main(String[] args){
int x1 = Integer.MAX_VALUE;
int x2 = 2;
int x = x1 + x2;
System.out.println("x1="+x1+"\nx2="+x2);
System.out.println("x1+x2="+x);
}
}
如上, 用int的能表示的最大值加2, 结果是多少?
结果为-2147483647
下面看一看是如何得到这个结果的
首先是x1的值为2147483647, 二进制形式
0111 1111 1111 1111 1111 1111 1111 1111
x2的值为2, 二进制形式
0000 0000 0000 0000 0000 0000 0000 0010
二者相加为
1000 0000 0000 0000 0000 0000 0000 0001
由于二者相加, 结果超出int最大范围, 导致溢出, 所以运算结果把符号位0替换成了1.
并且, 数值都是补码形式存储的, 所以二者相加结果为实际数值取反加1, 我们反向求出实际数值
先减1 (符号位不参与)
1000 0000 0000 0000 0000 0000 0000 0000
再取反 (符号位不参与)
1111 1111 1111 1111 1111 1111 1111 1111
得到的结果就是实际数值, 该数值即为-2147483647