开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第4天,点击查看活动详情
不管是在学java还是操作系统或者计算机组成原理都不可避免的会学到位运算。最近我在看一些算法题,也碰到了他。想了想,觉得可以整理整理我碰到的位运算。
什么是位运算?
在计算机里面,所有数据都是按照二进制方式存储,即不管你存储是图片还是数字,计算机都会把他转换成01形式存储,在这种状态下,对二进制数据进行(+ - * /)就是我们的位运算,也就是符号参与的二进制运算。
如果有:int a=3;int b=4;int c=a+b; 那么计算机底层是怎么做的呢?
- 第一步:二进制转换
- 3: 0 0 0 0 0 0 1 1
- 4: 0 0 0 0 0 1 0 0
- ————————————————————
- 7: 0 0 0 0 0 1 1 1
看到这里,是不是在想怎么把十进制转换二进制?下面就是第一个点,进制转换
进制转换
十进制 以0-9这九个数字组成,不能以0开头。 二进制: 由0和1两个数字组成 八进制: 由0-7数字组成,为了区分与其他进制的数字区别,开头都是以0开始 十六进制:由0-9和A-F组成。为了区分于其他数字的区别,开头都是以0x开始
本文主要讲解十进制转换成二进制。
十进制转二进制的转换原理:除以2,反向取余数,直到商为0终止。 即将某个十进制数除2得到的整数部分保留,作为第二次除2时的被除数,得到的余数依次记下,重复上述步骤,直到整数部分为0就结束,将所有得到的余数最终逆序输出,则为该十进制对应的二进制数。
如果是小数部分:采用乘2取整的方法(我目前很少碰到)
Java代码实现
- Integer b=Integer.toBinaryString(十进制整数)
- BigInteger b=Integer.toString(十进制整数, 2);
- 依照数学公式,程序中x%2的结果为余数,即二进制中最后一位数字,x=x/2即用新的x求余,最终我们要得出二进制数,就要将余数逆向输出,由于输出后只是表达方式不同(只有0,1),但仍然是十进制数,所以逆向输出就是:第一个得出的余数是个位数,第二个得出余数是十位数。故可以利用累乘10后再累加得出最终的二进制数。
public int Two(int x) {
int t=0;
int a;
for(int i=1;x>0;i=i*10) {
a=x%2;
x=x/2;
t=t+a*i;
}
return t;
}
快速十进制转换二进制参考表格:
| 二进制 | 十进制 |
|---|---|
| 0000 | 0 |
| 0001 | 1 |
| 0010 | 2 |
| 0011 | 3 |
| 0100 | 4 |
| 0101 | 5 |
| 0110 | 6 |
| 0111 | 7 |
| 1000 | 8 |
| 1001 | 9 |
| 1010 | 10 |
| 1011 | 11 |
| 1100 | 12 |
| 1111 | 13 |
运算符号
& 按位与
运算规则:
0&0=0 0&1=0 1&0=0 1&1=1
巧记:同1则1,有0则0
例如:3&5 即 0000 0011& 0000 0101 = 0000 0001,因此 3&5 的值得1。
与运算用途
-
清0 任何数和0做与运算,结果为0
-
取指定位数 当前为和1做与运算结果为当前数。比如取数 X=1010 1110 的低4位,只需要另找一个数Y,令Y的低4位为1,其余位为0,即Y=0000 1111,然后将X与Y进行按位与运算(X&Y=0000 1110)即可得到X的指定位。
-
判断奇偶 只要根据最未位是0还是1来决定,为0就是偶数,为1就是奇数。因此可以用if ((a & 1) == 0)代替if (a % 2 == 0)来判断a是不是偶数。
| 或运算符
运算规则:
0|0=0 0|1=1 1|0=1 1|1=1
有1则1,同0为0
例如:3|5即 0000 0011| 0000 0101 = 0000 0111,因此,3|5的值得7。
或运算用途 对数据的某些位数设置为1
任何位上的数和1做或运算,结果为1。 比如将数 X=1010 1110 的低4位设置为1,只需要另找一个数Y,令Y的低4位为1,其余位为0,即Y=0000 1111,然后将X与Y进行按位或运算(X|Y=1010 1111)即可得到。
^ 异或运算符
运算规则:
0^0=0 0^1=1 1^0=1 1^1=0
两个不相同结果是1,相同结果是0
异或几种性质
- 交换律
- 结合律 (a^b)^c == a^(b^c)
- 对于任何数x,都有 x^x=0,x^0=x
- 自反性: a^b^b=a^0=a; 异或的用途
- 翻转指定位数 比如将数 X=1010 1110 的低4位进行翻转,只需要另找一个数Y,令Y的低4位为1,其余位为0,即Y=0000 1111,然后将X与Y进行异或运算(X^Y=1010 0001)即可得到。
- 和0异或结果不变
左移右移
左移:将一个运算对象的各二进制位全部左移若干位(左边的二进制位丢弃,右边补0)。 右移:将一个数的各二进制位全部右移若干位,正数左补0,负数左补1,右边丢弃。
一些算法使用的
交换 a b 两个数
一般做法: int c=a;a=b;b=c
但是一般那种需要一个新变量,如果没有变量怎么办?优化一下: a=a+b;b=a-b;a=a-b
假设a=10,b=20 a=a+b a=30,b=20 b=a-b a=30,b=10 a=a-b a=20,b=10
但是这样可能会越界再次优化:a=a^b;b=a^b;a=a^b;
假设a=10,b=20 a=0000 1010 b=0001 0100 a=a^b;0000 1010 ^ 0001 0100 =0001 1110 b=a^b;0001 1110 ^ 0001 0100 =0000 1010 a=a^b;0001 1110 ^ 0000 1010 =0001 0100
到这里,交换两个数完成。虽然在平时交换一般使用的是用新变量那种,但是也需要了解了解其他的哦~
左移右移
x<<2就是x右移两位,再赋值,类似x+=2
3<<1 0000 0011 0000 0110 3>>1 0000 0011 _000 0001 _是符号位,原来是0就是0,原来是1就是1 0000 0001
3>>>1 无符号移动(都是0补位,不论符号:可能存在负数移动变成正数那种) 00000011 00000001
& 和 && 的区别
& 逻辑与,按位与
&& 短路与
逻辑符号算:
f&f=f;f&t=f;t&f=f;t&t=t
f&&f=f;f&&t=f;t&&f=f;t&&t=t
看上去两个非常相似,但是&&当第一个是f会发生短路,&&后的不运算返回f。只有第一个是t才会让&&后运算执行