写在前面
计算机中所有的数据二进制的形式存储在设备中。即 0、1 两种状态,计算机对二进制数据进行的运算(+、-、*、/)都是叫位运算,即将符号位共同参与运算的运算。
关于进制
进制是计算机中数据的一种表示方法。 N进制的数可以用0~(N-1) 的数表示, 超过9的用字母A-F 表示 。
- 十进制:用 0~9 的数表示 , 逢 10 进 1
- 二进制:由 0-1组成
- 八进制:由 0-7组成,逢 8 进 1
- 十六进制: 由 0-9,A-F组成。0-9 对应 0-9,A-F对应10-15。字母不区分大小写
进制的转换
二进制转十进制
二进制数的第0位的权值是2的0次方,第一位是2的1次方......
所以,设有一个二进制数:101100100,转换为十进制为(从右向左):
0x2 0 + 0x2 1 + 1x2 2 + 0x2 3 + 0x2 4 + 1x2 5 + 1x2 6 + 0x2 7 + 1x2 8 = 356
八进制转十进制
八进制数的第0位的权值是8的0次方,第一位是8的1次方......
所以,设有一个八进制数:1507,转换为十进制为(从右向左):
7x8 0 + 0x8 1 + 5x8 2 + 1x8 3 = 839
十六进制转十进制
十六进制数的第0位的权值是16的0次方,第一位是16的1次方......
所以,设有一个十六进制数2AF5,转换为十进制为(从右向左):
5x16 0 + Fx16 1 + Ax16 2 + 2x16 3 = 10997
快速的进行2进制,10进制,16进制的相互转换
二进制的8421
首先我们来看一个二进制数:1111,它是多少呢? 你可能还要这样计算:1×2º+1×2¹+1×2²+1×2³=1×1+1×2+1×4+1×8=15。
我们必须直接记住1111每一位的权值,并且是从高位往低位记:8、4、2、1。
即,最高位的权值为2³=8,然后依次是 2² =4,2¹=2,2º=1。
记住8 4 2 1,对于任意一个4位的二进制数,我们都可以很快算出它对应的10进制值。
接下来我们练习 通过 8421 的方式 进行 快速的计算 , 2,10,16进制的转换
1111 = 8 + 4 + 2 + 1 = 15 =F
1110 = 8 + 4 + 2 + 0 = 14= E
1101 = 8 + 4 + 0 + 1 = 13= D
1100 = 8 + 4 + 0 + 0 = 12 =C
1011 = 8 + 0 + 2 + 1 = 11= B
1010 = 8 + 0 + 2 + 0 = 10 =A
1001 = 8 + 0 + 0 + 1 =9 =9
……
0001 = 0 + 0 + 0 + 1 = 1= 1
0000 = 0 + 0 + 0 + 0 = 0= 0
-
二进制数转十六进制
以4位一段,分别转换为十六进制,如:
-
十六进制转二进制
反过来,当我们看到 FD时,如何迅速将此十六进制转二进制呢?
看到F,我们需知道它是15,然后15如何用8421凑呢?
应该是:8 + 4 + 2 + 1,所以四位全为1 :1111。
接着转换D,看到D,知道它是13,13如何用8421凑呢?
应该是:8 + 4 + 1,即:1101。
所以,FD转换为二进制数,为:1111 1101
-
十进制转二进制
由于十六进制转换成二进制相当直接,所以,我们需要将一个十进制数转换成二进制数时,也可以先转换成十六进制,然后再转换成二进制。 比如,十进制数 1234转换成二制数,如果要一直除以2,直接得到2进制数,需要计算较多次数。所以我们可以先除以16,得到16进制数:
1234÷16=77...2 77÷16=4...13(D) 4÷16=0...4
十六进制为:4D2
转二进制对应为:
0100 4 1101 D 0010 2
即十进制1234转二进制为:0100 1101 0010
-
二进制转十进制
同样,如果一个二进制数很长,我们需要将它转换成十进制数时,除了前面学过的方法是,我们还可以先将这个二进制转换成十六进制,然后再转换为10进制。如一个int类型的二进制数如下:
0110 1101 1110 0101 1010 1111 0001 1011
我们按四位一组转换为十六进制:6 D E 5 A F 1 B
十六进制转化为十进制:
Bx16 0 + 1x16 1 + Fx16 2 + Ax16 3 + 5x16 4 + Ex16 5 + Dx16 6 + 6x16 7 = 1843769115
-
十进制转十六进制
采余数定理分解,例如将487710转成十六进制:
487710÷16=30481...14(E) 30481÷16=1905...1 1905÷16=119...1 119÷16=7...7 7÷16=0...7
487710(10) = 7711E(16)
位运算
计算机中的计算都是以二进制来进行运算的,因此相比在代码中直接使用(+、-、*、/)运算符,合理使用位运算符能提高代码的执行效率。
符号 | 描述 | 运算规则 |
---|---|---|
& | 位与 | 两个位都为1时,结果才为1(1&1=1,0&0=0,1&0=0) |
| | 位或 | 两个位都为0时,结果才为0(1|1=1,0|0=0,1|0=1) |
~ | 位非(取反) | 1变0,0变1 (~1=0 ,~0=1) |
位异或 | 两个位相同为0,相异为1(1 ^ 1=0,1 ^ 0=1, 0 ^ 0=0) | |
>> | 有符号右移 | 若正数,高位补0,负数,高位补1 |
<< | 有符号左移 | 若正数,高位补0,负数,高位补1 |
>>> | 无符号右移 | 不论正负,高位均补0 |
与(&)
4 & 6 = 4
首先我们需要把两个十进制的数转换成二进制
4 0 1 0 0
6 0 1 1 0
----------
4 0 1 0 0
用途
-
清零:若想将一个单元清零,只要与一个各位都为0的数值相与,结果就为零
-
判断奇偶:只要根据最末位判断是0还是1就可以判断,是0就是偶数,是1就是奇数
if ((a & 1) == 0) //如果a是偶数 代替 if (a % 2 == 0)
或(|)
4 & 6 = 6
首先我们需要把两个十进制的数转换成二进制
4 0 1 0 0
6 0 1 1 0
----------
6 0 1 1 0
用途
- 常用来对一个数据的某些位设置为1:若要将一个数X=10101100的低四位设置为1,那么令Y=00001111,X与Y相或的结果就是将X的低四位设置为1(X | Y = 10101111)
非(~)
在Java中,所有数据的表示方法都是以补码的形式表示,如果没有特殊说明,Java中的数据类型默认是int,int数据类型是占4个字节,1字节为8位,所以int为32位,32bit。
补码与原码关系:正数补码与原码相同,负数补码是原码减1后取反
例如:5
原码是:00000000 00000000 00000000 00000101
补码是:00000000 00000000 00000000 00000101(计算机内存储)
例如:-5
原码:10000000 00000000 00000000 00000101
补码:11111111 11111111 11111111 11111011(计算机内存储)
注意:二进制中,最高位是符号位1表示负数,0表示正数
了解了原码补码我们来看位非~运算符
例:~4
4 0 1 0 0
----------
-5 1 0 1 1
4转为二进制是:0100
补码为:00000000 00000000 00000000 00000100
取反为:11111111 11111111 11111111 11111011(这就是~4在计算机存储的补码)
需要将补码计算出原码然后转化为十进制,高位不变,取反+1
10000000 00000000 00000000 00000101
转为十进制为:-5
所以 ~4 = -5
异或(^)
4 ^ 6 = 6
首先我们需要把两个十进制的数转换成二进制
4 0 1 0 0
6 0 1 1 0
----------
2 0 0 1 0
相同为0,不同为1
用途
-
交换两个数:一个数和另一个数异或两次得到还是原来的数
//不使用临时变量交换两个数 void swap ( int a, int b ) { if ( a != b) { a = a ^ b; b = a ^ b;//a与b异或两次了,现在值为a a = a ^ b;//用原来的a、b表示的话,这句代码的意思是a^b^a } }
右移(>>)
4>>1 = 2
4转为二进制是:0100
正数,高位补0,负数,高位补1
左移(<<)
4<<1 = 8
4转为二进制是:0100
正数,高位补0,负数,高位补1
负数在非运算中已做说明,这里不在演示。
无符号右移(>>>)
无符号右移(>>>)只对32位和64位有意义。
在移动位的时候与右移运算符的移动方式一样的,区别只在于补位的时候不管是0还是1,都补0。
有趣的取模性质
取模a % (2^n) 等价于 a & (2^n - 1),所以在map里的数组个数一定是2的乘方数,计算key值在哪个元素中的时候,就用位运算来快速定位。
public static void main(String[] args) {
//取模a % (2^n) 等价于 a & (2^n - 1)
System.out.println("the 345 % 16 is : " + (345 % 16)); //9
System.out.println("the 345 % 16 is : " + (345 & (16 - 1)));//9
}