2进制位运算基础笔记 满满干货呀,赶紧点赞收藏吧!!!
字节和位数
在java中基本数据类型所占的字节数,一个字节是8位;
数据类型 | 字节 | 位数 |
---|---|---|
byte | 1 | 8 |
boolean | 1 | 8 |
short | 2 | 16 |
int | 4 | 32 |
long | 8 | 64 |
float | 4 | 32 |
double | 8 | 64 |
char | 2 | 16 |
2进制位运算
概念
原码、反码、补码
所有计算机中这些码可以理解为一种规定标准,就是说计算机里以何种标准来存储二进制;
另外在计算机中规定:
- 1.二进制的最高位是符号位: 0表示正数,1表示负数
- 2.正数的原码,反码,补码都一样 (三码合一)
- 3.负数的反码=它的原码符号位不变,其它位取反(0->1,1->0)
- 4.负数的补码=它的反码+1
- 5.0的反码,补码都是0
- 6.在计算机运算的时候,都是以补码的方式来运算的
原码
原码就是一个数的二进制形式
比如-8的二进制数表示:
11111111 11111111 11111111 11111000
其中,最高位为符号位:正数为0,负数为1,剩下的位表示数值。
反码
反码就是在原码的基础上,符号位不变其他位按位取反 [取反就是0变1,1变0]
补码
补码就是在反码的基础上+1
比如 -8从二进制是如何算出来的呢?
-8的二进制
原码
10000000 00000000 00000000 00001000
反码
11111111 11111111 11111111 11110111
补码
11111111 11111111 11111111 11111000
位运算
在二进制里面
- 整型int使用32个字节,32位,其中最高位为0表示的是正数,最高位为1表示的是负数
& (按位与)
- 两位都为1,结果才是1
int a = 8;// 8(10)==00000000 00000000 00000000 00001000(2)
int b = 9;// 9(10)==00000000 00000000 00000000 00001001(2)
int c = a & b;// == 00000000 00000000 00000000 00001000(2)
System.out.println(c);// c=8
按位与的应用
可以判断一个数x的奇偶性
- x&1=0,说明x是偶数
- x&1=1,说明x是奇数
System.out.println(a & 1);// 结果0,说明a是偶数
System.out.println(b & 1);// 结果1,说明b是奇数
保留指定的位数
比如想保留数a的后8位
- 0xff是16进制,转换二进制00000000 00000000 11111111 1111111
System.out.println(a = a & 0xff);// ==00000000 00000000 00000000 00001000(2)
System.out.println(Integer.toBinaryString(a & 0xff));
| ( 按位或)
- 只要有一个为1,结果就为1
int a = 8;// 8(10)==00000000 00000000 00000000 00001000(2)
int b = 9;// 9(10)==00000000 00000000 00000000 00001001(2)
int c = a | b;// == 00000000 00000000 00000000 00001001(2)
System.out.println(c);// c=9
按位或的应用;
将一个数x指定位全部换成1
比如上面的a
//数a的后8位全部变成1
System.out.println(a = a | 0xff);//== 00000000 00000000 00000000 11111111(2)
System.out.println(Integer.toBinaryString(a | 0xff));
^ (按位异或)
- 相应位不同为1,相同为0
int a = 8;// 8(10)==00000000 00000000 00000000 00001000(2)
int b = 9;// 9(10)==00000000 00000000 00000000 00001001(2)
int c = a ^ b;// == 00000000 00000000 00000000 00000001(2)
System.out.println(c);// c=1
按位异或的应用:
定位反转
将一个数x的0位变成1,1位变成0
System.out.println(a ^ 0xff);// == 00000000 00000000 00000000 11110111(2)
System.out.println(Integer.toBinaryString(a ^ 0xff));
交换a和b的数值
a = a ^ b;
b = b ^ a;
a = a ^ b;
System.out.println(a);// 9
System.out.println(b);// 8
~(按位取反)
- 将一个位上的数按位取反
<< (左移)
- <<左移将一个运算对象的各二进制位全部左移若干位左边的二进制位丢弃,右边补0
int a = 8;// 8(10)== 00000000 00000000 00000000 00001000(2)
int b = -8;// -8(10)=11111111 11111111 11111111 11111000(2)
System.out.println(a << 1);// 00000000 00000000 00000000 00010000(2)==16(10)
System.out.println(b << 1);// 11111111 11111111 11111111 11110000(2)==-16(10)
左移的规律:
一个数y左移n位(y<< n),就相当于这个数乘以 2n
>> (右移)
- 这个表示的是有符号右移
- 将一个运算对象的各个二进制位全部右移若干位
- 是正数,左边的二进制位补0
- 是负数,左边二进制位补1
- 右边统统舍弃
int a = 8;// 8(10)== 00000000 00000000 00000000 00001000(2)
int b = -8;// -8(10)=11111111 11111111 11111111 11111000(2)
System.out.println(a >> 1);// 00000000 00000000 00000000 00000100(2)==16(4)
System.out.println(b >> 1);// 11111111 11111111 11111111 11111100(2)==-16(4)
右移的规律
一个数y右移n位(y>> n),就相当于这个数除以 2n
>>> (无符号右移)
- 无符号右移
- 各个位向右移指定的位数
- 右移后左边空出的位用零来填充
- 移除右边的位被舍弃
int a = 8;// 8(10)== 00000000 00000000 00000000 00001000(2)
int b = -8;// -(10)=11111111 11111111 11111111 11111000(2)
System.out.println(a >>> 1);// 00000000 00000000 00000000 00000100(2)==4(4)
System.out.println(b >>> 1);// 01111111 11111111 11111111 11111100(2)==2147483644(4)
位运算小技巧
判断int型变量a是奇数还是偶数
a&1 = 0 //偶数
a&1 = 1 //奇数
求平均值
比如有两个int类型变量x、y,首先要求x+y的和,再除以2,但是有可能x+y的结果会超过int的最大表示范围,所以位运算就派上用场啦
(x&y)+((x^y)>>1);
对于一个大于0的整数,判断它是不是2的几次方
((x&(x-1))==0)&&(x!=0);
比如有两个int类型变量x、y,要求两者数字交换
位运算的实现方法:性能绝对高效
x ^= y;
y ^= x;
x ^= y;
求绝对值
int abs( int x )
{
int y ;
y = x >> 31 ;
return (x^y)-y ;
//or: (x+y)^y
}
取模运算
采用位运算实现:
a % (2^n) 等价于 a & (2^n - 1)
乘法运算
采用位运算实现
a * (2^n) 等价于 a << n
除法运算转化成位运算
a / (2^n) 等价于 a>> n
求相反数
(~x+1)
a % 2
a % 2 等价于 a & 1
打印二进制数
private static void print(int num) {
for (int i = 31; i >= 0; i--) {
System.out.print((num & (1 << i)) == 0 ? '0' : '1');
}
System.out.println();
}