位运算

位运算

二月 08, 2021

##位运算基础概念

1、原码
一个正数,按照绝对值大小转换成二进制数,称为原码
2、反码
将二进制数按位取反,所得的新二进制数称为原二进制数的反码
其实就是把原码中的0变为1,1变为0
例如:0000 0101 和1111 1010就是互为反码
3、补码
在反码的基础上加1称为补码,一般在算负数的时候会用到

###1、正整数转换二进制
除二取余,然后倒序排列,高位补零。

43 21 10 5 2 1
/2 /2 /2 /2 /2 /2
1 1 0 1 0 1
从左至右得出二进制 110101 十进制为52
高位补零 00110100

###2、负数二进制
先将对应的正整数转换成二进制
对二进制取反,这边有个不一样的地方,原来那个正数的补位都是0,但是你取反了,那就证明负数补位的时候,要补1
然后对结果再加1(这里的1,是十进制的1,但是十进制的1对应的二进制就是00000001)
23 11 5 2 1
/2 /2 /2 /2 /2
1 1 1 0 1
负数从右至左得出 10111
取反 01000 加一 01001

##位运算
1、& 与
规则:先将两个数字转换为二进制,然后每一位进行匹配
只有当两个位置上都是1的时候,才会返回1
例子:9&12
9:1001
12:1100
所以结果应该是:1000=》转换为十进制:8

2、| 或
规则:先将两个数字转换为二进制,然后每一位进行匹配
两个位只要有一个为1,那么结果就是1,否则就为0。
例子:9|12
9:1001
12:1100
所以结果应该是:1101=》转换为十进制:13

3、^ 异或
规则:先将两个数字转换为二进制,然后每一位进行匹配
两个操作数的位,相同则结果为0,不同则结果为1。
0 ^ 1 =1,1 ^ 1 = 0,0 ^ 0 = 0,1 ^ 0 = 1
例子:9^12
9:1001
12:1100
所以结果应该是:0101=》转换为十进制:5

4、~ 取反
规则:这个是对一个数字的操作
先将这个数字转换为二进制
然后每个位上的数字,0变成1,1变成0
例子:~9
9:1001
~9:0110
所以结果应该是0110=》转换为十进制:6
呵呵,你自己试试,答案是错的。。不是6,答案是-10
为什么?
先说一个概念int类型是4字节,1字节是8位,所以int类型有32位
然后,9的值是1001,其实你全部写出来应该是0000 0000 000…(前面有28个0)然后1001
所以对9取反,不能简单的写成0110,因为0110代表的是0000 0000 000…(前面有28个0)然后0110
~9:1111 1111 1111 1111 1111 1111 1111 0110
接着你可以在代码中试试:
String i = Integer.toBinaryString(-10);
System.out.println(i);
System.out.println(i.length());
打印出来的就是:
11111111111111111111111111110110
32
结论:所以这里就要说到,在上文中提到的二进制的有符号数和无符号数
再重新阐述一次:简单来说,例如byte长度是8位,无符号数的情况下,1111 1111 =》255
有符号数的情况下,因为最高位1代表负号,0代表正号,所以 0111 1111 =》127,所以1000 0000 =》-128

所以你还记得byte类型能表示的长度是-128—127吗,就是这个原因
那么在java中几乎所有的正数取反,会得到负数,负数取反会得到正数!
比如1000 0001 这个二进制的有符号数,他代表的值就是-127
所以这是取反操作的一个坑,也是不少网络给出的什么二进制转换器输入1000 0000得到的值为128的原因(因为他识别成无符号二进制数字)

5、>> (右移运算符)和<< (左移运算符)

这两个东西,放在一起记录,是因为这两个操作是一样的,就是一个位移操作
1、举例1、12>>2
操作:
先将12转换为二进制 ==》1100
然后把整体向右移动两位 ==》0011
最后转换为十进制 ==》 12的0次方+12的1次方=3
所以答案:3
2、举例2、12<<2 操作:="" 先将12转换为二进制="=》1100" 然后把整体向左移动两位="=》110000" 最后转换为十进制="=》" 1*2的4次方+1*2的5次方="48" 所以答案:48="" 结论:所以也能简单的理解为="">>3就是原来的数字除以2的3次方,<<3就是乘以2的3次方