文章目录
1. 原码、反码、补码
1.1 原码
就是二进制定点表示法,即最高位为符号位:“0”表示正,“1”表示负,其余位表示数值的大小。
该数字不进行其他操作时数字最原始的二进制表示, 对于原码来说,绝对值相等的正数和负数只有符号位不同。
1.2 反码
正数的反码与其原码相同;
负数的反码是对其原码逐位取反,但符号位除外。(只需要将原码除符号位以外的位数取反,即0改为1,1改为0)
1.3 补码
正数的补码与其原码相同;
负数的补码是在其反码的末位加1;
现在的计算机都用补码存储整形数值。
计算机为什么有反码和补码?
有人会有疑惑为什么要用反码,补码,不直接用原码呢?
先搞清楚一点反码、补码、原码是针对二进制数而言,计算机若用原码相加减,正数加正数不会出错,然而正数和负数原码相加就会出错。说白了,补码、反码就是为了简化减法而来的,将减号化为负数后再将负数化为补码求加法,就跟正数没关系了!
不管是正整数还是正小数,原码,反码,补码都全部相同。计算机中所有数都是以补码形式存储的。
1.10+(1)时:1010 + 0001 = 1011,即11。
2.10+(-1)时:00001010 + 10000001 = 10001011 ,即 -11 (原码参与加法运算)
3.10+(-1)时:00001010 + 11111111 = 00001001,即 9 (补码参与加法运算)
1.4 byte的最大值
八位二进制中正数最大是0111 1111(第一位是符号位),所以byte正数范围是(0-127),共有2^7=128个数值;
1.5 byte的最小值
八位二进制中负数计算需要用反码末位+1得到补码,所以1111 1111补码就是1000 0001=-1,一直到1000 0001补码是1111 1111= -127,而1000 0000的补码是1000 0000也就是-0,没有意义,此处计算机将它计为-128,故一个字节的取值范围是[-128,127]。
2. 位运算
2.1 & 与
两个位都为1时,结果才为1
2.2 | 或
两个位都为0时,结果才为0;
或者表述为,有一个是1,结果就是1,否则是0。
2.3 ~ 非
0变1,1变0
2.4 ^ 异或
相同为0,不同为1
2.5 << 左移 (没有无符号左移)
符号位不变,正数负数都是低位用0补齐,不管对于正数还是负数,都相当于乘以2^n
2.6 >> 右移 (有符号右移)
高位用符号位补齐(高位正数用用0补,负数用1补)
2.7 >>> 无符号右移
正数负数高位都用0补(由于符号位被拱占,导致负数变成正数)
2.8 有符号右移和无符号右移的区别
测试代码
public class BitArithmetic {
public static void main(String[] args) {
// 下面展示有符号右移和无符号右移的区别
// 有符号右移( >> )
int i1 = 128;
int r1 = i1 >> 1;
int r11 = i1 >> 2;
int i2 = -128;
int r2 = i2 >> 1;
int r22 = i2 >> 2;
// 无符号右移( >>> )
int i3 = 128;
int r3 = i3 >>> 1;
int r33 = i3 >>> 2;
int i4 = -128;
int r4 = i4 >>> 1;
int r44 = i4 >>> 2;
// 打印结果
print(i1, 1, r1, ">>");
print(i1, 2, r11, ">>");
print(i2, 1, r2, ">>");
print(i2, 2, r22, ">>");
print(i3, 1, r3, ">>>");
print(i3, 2, r33, ">>>");
print(i4, 1, r4, ">>>");
print(i4, 2, r44, ">>>");
print(Integer.MAX_VALUE, 1, r44, ">>");
print(Integer.MAX_VALUE, 1, r44, ">>>");
print(Integer.MIN_VALUE, 1, r44, ">>");
print(Integer.MIN_VALUE, 1, r44, ">>>");
}
private static void print(int i, int y, int r, String operator) {
System.out.println(i + " " + operator + " " + y + " = " + r);
System.out.println("二进制表示: " + getIntBits(i) + " " + operator + " " + y + " = " + getIntBits(r));
System.out.println("====================");
}
private static String getIntBits(int num) {
String str = "";
for (int i = 31; i >= 0; i--) {
str = str + ((num & (1 << i)) == 0 ? "0" : "1");
}
return str;
}
}
打印结果
128 >> 1 = 64
二进制表示: 00000000000000000000000010000000 >> 1 = 00000000000000000000000001000000
====================
128 >> 2 = 32
二进制表示: 00000000000000000000000010000000 >> 2 = 00000000000000000000000000100000
====================
-128 >> 1 = -64
二进制表示: 11111111111111111111111110000000 >> 1 = 11111111111111111111111111000000
====================
-128 >> 2 = -32
二进制表示: 11111111111111111111111110000000 >> 2 = 11111111111111111111111111100000
====================
128 >>> 1 = 64
二进制表示: 00000000000000000000000010000000 >>> 1 = 00000000000000000000000001000000
====================
128 >>> 2 = 32
二进制表示: 00000000000000000000000010000000 >>> 2 = 00000000000000000000000000100000
====================
-128 >>> 1 = 2147483584
二进制表示: 11111111111111111111111110000000 >>> 1 = 01111111111111111111111111000000
====================
-128 >>> 2 = 1073741792
二进制表示: 11111111111111111111111110000000 >>> 2 = 00111111111111111111111111100000
====================
2147483647 >> 1 = 1073741792
二进制表示: 01111111111111111111111111111111 >> 1 = 00111111111111111111111111100000
====================
2147483647 >>> 1 = 1073741792
二进制表示: 01111111111111111111111111111111 >>> 1 = 00111111111111111111111111100000
====================
-2147483648 >> 1 = 1073741792
二进制表示: 10000000000000000000000000000000 >> 1 = 00111111111111111111111111100000
====================
-2147483648 >>> 1 = 1073741792
二进制表示: 10000000000000000000000000000000 >>> 1 = 00111111111111111111111111100000
====================