1, 二进制
数据在内存中是用二进制存储的,二进制是指由0,1两个元素组成。
其常见的编码方式有三种:原码,反码,补码
2 ,位
内存中最小存储单元是位,也称为bit。常常用8个bit存储一个字符,即1Byte=8bit。
3 ,位操作
是指cpu对内存中的二进制数进行操作。
包括&(与)、|(或)、^(异或)、~(非)、<<(按位左移)、>>(按位右移)六个操作符。
3.1 双目运算符
是指参与运算的有两个数。下面括号内分别表示两个数。
&:if (1,1)?1:0
|:if (1,0) or (0,1) ?1:0
^:if (0,0) or (1,1)?0:1
<<:向左按位进N位,低位补0。
>>:向右按位进N位,低位舍弃。
3.2 单目运算符
是指参与运算的数的本身,即一个数。
~:if 1?0:1
4, 原码
指真实的二进制编码。
当数是有符号的整数,最高位用来表示正负,1表示负,0表示正,其余位表示数值的大小。
8位原码
二进制 有符号 无符号 00000000 +0 0 00000001 1 1 ... ... ... 01111111 127 127 10000000 −0 128 10000001 −1 129 ... ... ... 11111111 −127 255即十进制5=二进制0000 0101,-5=1000 0101。
一个字符所占的空间是00000000~11111111.
两个正数相加,即逢2进1.
两个负数的加法就很简单了,把结果保留符号位,然后按照正数加法运算即可。
由于cpu中没有减法器电路,原码就没办法执行减法运算,只能由一个正数加一个负数,显示是计算出来的结果是错误的。
比如:5+(-)5=1000 1010=-10(错误)
注意到此时有符号数:~(+0)=-127,~1=-126...~127=-0
所以引出反码。
5, 反码
反码是指对有符号数逐位取反,保留符号位;无符号数反码与原码相同。
即:反码=~原码|1000 0000
8位反码
二进制值 反码表示 无符号数表示 00000000 +0 0 00000001 1 1 ... ... ... 01111101 125 125 01111110 126 126 01111111 127 127 10000000 −127 128 10000001 −126 129 10000010 −125 130 ... ... ... 11111110 −1 254 11111111 −0 255如上,注意到实际上是把原码表中的负数部分上下对调。即-127调到-0的位置,如此类推。
如何调换位置呢?想一想链表,原理类似,只要把除符号位以外的元素进1位即可。
那么反码+反码的结果就是表中所示,如果要映射到原码表,进一位即可。
所以减法的计算公式:结果+0000 0001(十进制1)
下面来计算减法:
那么(-1)+2=1111 1110
+ 0000 0010
+ 0000 0001
= 0000 0001
6,补码
补码是指对有符号数逐位取反,保留符号位,然后再加1;无符号数反码与原码相同。
回头再看看反码的减法,需要进行三步操作,即建立反码表、加法、映射到原码表(结果加1)。而且表中还存在两个0,浪费了宝贵的内存空间。
为了解决进位加1,和减少内存空间的浪费,所以提出了补码。
补码是反码表加1,即补码=~原码|1000 0000+ 0000 0001
8位补码
二进制值 补码表示 无符号数表示 00000000 0 0 00000001 1 1 ... ... ... 01111110 126 126 01111111 127 1275 10000000 −128 128 10000001 −127 129 10000010 −126 130 ... ... ... 11111110 −2 254 11111111 −1 255下面来计算减法:
那么(-1)+2=1111 1111
+ 0000 0010
= 0000 0001
内存中的数是用补码表存储的。
7,常用的位操作技巧
7.1 判断一个正整数是奇数还是偶数
很显然在二进制中只要判断最后一位是否是0还是1,0即偶数,1为奇数。
即:a&1
实际上我们可以看到&起到一个只对自己关心的位置操作的作用。有的地方叫着掩码也正是这个意思。
如果只是想操作某一个数的第2,3位,可以用a&0000 0110
7.2 交换数不用临时变量
x^=y;
y^=x;
x^=y;
参考资料来源:
1.
2.
3.
4.
5.