每个 bit 是 0 或1;
数字、字符串、集合等用不同方式编码为 bits,以告诉计算机该干什么;在数字世界里可以通过各种模拟信号来对 bit 进行量化
为什么使用 bit?(电子实现)
bit 可以通过二进制表示,例如:
$15213_{10}\rightarrow 11101101101101_{2}$
$1.20_{10}\rightarrow 1.00110011[0011]…_{2}$
$1.5213_{10}\rightarrow 1.1101101101101_2\times2^{13}$
Byte = 8 Bits
表示范围:$ 00000000_2\ to\ 11111111_2 $ ,十进制:$ 0_{10}\ to\ 255_{10} $ ,十六进制:$00_{16}\ to\ FF_{16}$。
| Hex | Decimal | Binary | Hex | Decimal | Binary | 
|---|---|---|---|---|---|
| 0 | 0 | 0000 | 8 | 8 | 1000 | 
| 1 | 1 | 0001 | 9 | 9 | 1001 | 
| 2 | 2 | 0010 | A | 10 | 1010 | 
| 3 | 3 | 0011 | B | 11 | 1011 | 
| 4 | 4 | 0100 | C | 12 | 1100 | 
| 5 | 5 | 0101 | D | 13 | 1101 | 
| 6 | 6 | 0110 | E | 14 | 1110 | 
| 7 | 7 | 0111 | F | 15 | 1111 | 
十六进制使用 '0' ~ '9' 和 ’A‘ ~ ’F‘;
$FA1D37B_{16}$ 在 C 语言中写为:0xFA1D37Bor0xfa1d37b。
C 语言中的数据类型的字节数:
| 数据类型 | Typical 32-bit | Typical 64-bit | x86-64 | 
|---|---|---|---|
| char | 1 | 1 | 1 | 
| short | 2 | 2 | 2 | 
| int | 4 | 4 | 4 | 
| long | 4 | 8 | 8 | 
| float | 4 | 4 | 4 | 
| double | 8 | 8 | 8 | 
| long double | - | - | 10/16 | 
| pointer | 4 | 8 | 8 | 
将True编码为1,False编码为0。0,1作为了逻辑最基本的值。布尔运算包括:与&(and)、或|(or)、非~(not)、异或^(Exclusive-Or,xor)。
| 运算 | 条件 | 简记 | 
|---|---|---|
| And | A&B=1当且仅当A=1 and B=1 | 同真为真 | 
| Or | A\|B=1当A=1 or B=1 | 有真为真 | 
| Not | ~A=1当且仅当A=0 | 真假互换 | 
| Xor | A^B=1当且仅当A!=B | 相异为真 | 
当我们操作连续的比特时,可以视为对每个比特位进行了布尔操作。将连续的比特从左到右编号,并将1所在的位数记录,得到比特数和集合的一一对应关系,如下:
| 比特数/编号 | 集合 | 
|---|---|
| 01101001 76543210 | {0,3,5,6} | 
| 01010101 76543210 | {0,2,4,6} | 
那么布尔操作也可以视为集合的运算,如下:
| 布尔操作 | 结果 | 结果集合 | 集合操作 | 
|---|---|---|---|
| & | 01000001 | {0,6} | 交集 | 
| \| | 01111101 | {0,2,3,4,5,6} | 并集 | 
| ~ | 10101010 | {1,3,5,7} | 补集 | 
| ^ | 00111100 | {2,3,4,5} | 对称差集 | 
逻辑运算包括:&&,||和!,将0视为False,所有非0数视为True,并且总返回0或1。
逻辑运算会导致提前终止(Early termination)。
example:
!0x41 -> 0x00
!0x00 -> 0x01
!!0x41 -> 0x01
0x69 && 0x55 -> 0x01
0x69 || 0x55 -> 0x01
p && *p(一种短路逻辑运算表达式,用来做指针判空和间接访问指针指向内容的判断或保护操作)
位运算包括左移和右移操作,后者又细分为逻辑右移和算数右移。
Left Shift左移:x << y将位向量x左移y位。
左侧的位将被丢弃,右侧空位由0补足。
Right Shift右移:x >> y将位向量x右移y位。
右侧的位将被丢弃,逻辑右移(Logical shift)会用0填补左侧空位,算数右移(Arithmetic shift)会用原最高位来填补左侧空位。
当位移量小于0或大于等于位向量长度,会发生未定义行为(Undefined Behavior)。
example:
| x | « 3 | Log. » 2 | Arith. » 2 | 
|---|---|---|---|
| 01100010 | 00010000 | 00011000 | 00011000 | 
| 10100010 | 00010000 | 00101000 | 11101000 | 
计算机表示负数通常通过二进制补码(Two’s Complement) 表示:
| Unsigned | Two’s Complement | 
|---|---|
| $ B2U(X)=\sum_{i=0}^{w-1}x_i\cdot 2^i $ | $ B2T(X)=-x_{w-1}\cdot2^{w-1}+\sum_{i=0}^{w-2}x_i\cdot 2^i $ | 
其中第w-1位称为符号位(Sign Bit),1为负0为正。
用二进制补码表示负数时,通常先求其正数的二进制表示,然后逐位取反,最后加 1 。
例如:15213:00111011 01101101,而-15213:11000100 10010011 。
对于无符号整数,其表示范围是0到 2的位数次方;而有符号整数的范围是$-2^{w-1}$到$2^{w-1}-1$。
| UMAX | UMIN | TMAX | TMIN | Minus 1 | 
|---|---|---|---|---|
| 11111111 11111111=65535 | 00000000 00000000=0 | 01111111 11111111=32767 | 10000000 00000000=-32768 | 11111111 11111111=-1 | 
UMAX = TMAX * 2 + 1 = TMAX - TMIN,TMAX = - TMIN - 1
在两者做出比较时,如果出现 signed 和 unsigned 混合的情况,均被视为 unsigned。
如果要将一个w位整数 扩展(Expanding) 为w+k位整数,只需在前面复制原有的最高位;如果将数据截断(Truncating),两者都会被重新解释,Unsigned会出现模运算,Signed也会表现出类似于模运算的表现。