原码反码补码及简单应用
0 前提
在Java中,所有数据的表示方式都是以补码形式来表示
在Java中,所有数据的表示方式都是以补码形式来表示
在Java中,所有数据的表示方式都是以补码形式来表示
public static void main(String[] args) {
int num = 5;
System.out.println(num + "的补码 " + Integer.toBinaryString(num));
num = -1;
System.out.println(num + "的补码 " + Integer.toBinaryString(num));
num = -3;
System.out.println(num + "的补码 " + Integer.toBinaryString(num));
}
# 5的补码 101 #int是32位长度 但是前面都是0 省略了
# -1的补码 11111111111111111111111111111111
# -3的补码 11111111111111111111111111111101
0.1 机器数
一个数在计算机中的二进制表示形式, 叫做这个数的机器数。机器数是带符号的,在计算机用一个数的最高位存放符号, 正数0,负数为1
比如,十进制中的数 +3 ,计算机字长为8位,转换成二进制就是0000 0011。如果是 -3 ,就是 1111 1101 。那么,这里的 00000011 和 1111 1101 就是机器数。 机器数包含了符号和数值部分。
0.2 真值
因为第一位是符号位,所以机器数的形式值就不能很好的表示真正的数值。
例如上面的有符号数1111 1101(8位),其最高位1代表负,其真正数值是 -3 而不是形式值253(1111 1101按无符号整数转换成十进制等于253)。所以,为区别起见,将带符号位的机器数对应的真正数值称为机器数的真值。
例:0000 0001的真值 = +000 0001 = +1,1000 0001的真值 = –0111 1111 = –127;这里所说的比如-3二进制代码为10000011,就是我们计算机里面对-3表示的原码
1 规定
1.1 原码
原码:原码就是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值.
比如如果是8位二进制
[+1]原 = 0000 0001
[-1]原 = 1000 0001
[-3]原 = 1000 0011
比如如果是32位二进制
[+1]原 = 0000 0000 0000 0000 0000 0000 0000 0001
[-3]原 = 1000 0000 0000 0000 0000 0000 0000 0011
1.2 反码
反码:正数的反码与其原码相同;负数的反码是对其原码逐位取反,但符号位除外
8位二进制
[+1] = [ 0000 0001 ]原码 = [ 0000 0001 ]反码;
[-1] = [ 1000 0001 ]原码 = [ 1111 1110 ]反码;
1.3 补码
补码:正数的补码为其本身,负数的补码为其反码再加1
8位二进制
[+1]=[0000 0001]原码=[0000 0001]反码=[0000 0001]补码
[-1] =[1000 0001]原码=[1111 1110]反码=[1111 1111]补码
补码的补码为原码
2 总结
-
在Java中,所有数据的表示方式都是以补码形式来表示
-
正数:原码、反码、补码相同
-
负数:符号位(最高位)为1,其余各位是对原码取反是反码,然后反码加1是补码
3 二进制运算
- 与 (&)按位与运算
- 或 (|)按位或运算
- 异或 (^)异或运算
- 非(~)运算符
3.1 测试1
public static void main(String[] args) {
int num = ~5;
System.out.println(num + "的补码 " + Integer.toBinaryString(num));
}
#-6的补码 11111111111111111111111111111010
解释
5非运算为什么是-6?
-
5对应补码 0000 0101;
-
5取非(所有二进制位上取非):1111 1010
-
求补码1111 1010的原码,由补码的补码就是原码知:
[1111 1010] -> 反码 [1000 0101] ->补码 [1000 0110]
则 补码1111 1010的原码为1000 0110。
原码为1000 0110对应的真值为最高位1为负数,各级求和-1*(4*1 + 2*1)= -6
注意,取非和取反码不一样
-
取非是所有位上都取反;
-
取反码,最高位即符号位不取反,其他位取反
3.2 测试2
位移运算:
- >> n 右移n位,一个正数的补码整体右移n位,不足补0,负数最高位补1
- << m 左移m位,一个数的补码整体左移m位,不足补0
public static void main(String[] args) {
int num = 5 << 2;
System.out.println(num + "的补码 " + Integer.toBinaryString(num));
num = 5 >> 5;
System.out.println(num + "的补码 " + Integer.toBinaryString(num));
}
# 20的补码 10100
# 0的补码 0
解释
左移:
- 5的补码 0000 0101;
- 先左移两位后:0001 0100;(二进制补码整体左移两位,末位空出的补上0)
- 0001 0100计算后1*(16 + 4)= 20;
右移:
- 5的补码 0000 0101;
- 先右移五位后:0000 0000;
- 对应0
注意:
- 负数的位移运算要小心,负数右移最高位补的是1,而不是0了
3.3 应用
3.3.1 快速计算奇数还是偶数
public static void main(String[] args) {
int num = -150;
if((num & 1) == 0){
System.out.println("偶数");
}else {
System.out.println("奇数");
}
}
3.3.2 快速计算2^n(2的n次方)
public static void main(String[] args) {
System.out.println(1 << 16);
}
注意:整数默认是int,而int是32位有符号整数,取值范围-2^31 到(2^31 -1)
所以一个数的左移不要超过范围了。