大端与小端
将物理内存构造成一个字节数组,叫虚拟内存,其中每个字节都有一个序号,叫地址,所有地址的集合叫虚拟地址空间。CPU的位数,决定了寻址能力。比如32位的CPU,只能访问到地址为0-(2^32-1)的内存单元,所以32位的机器只能有4G内存大小。
一个int类型的整数,在内存中通常表示为4个字节,所以需要4个连续的内存单元去存储。这时候就涉及到了存储顺序的问题。是将低权重的字节放在低地址空间还是高地址空间。将低权重的字节放在低地址空间的模式成为小端。将高权重放低地址的称为大端。
int a = 0x12345678;
现在将a地址开始的四个字节依次读出,如果是小端模式,则读出结果为:0x78 0x56 0x34 0x12。
如果是大端模式,则结果为:0x12 0x32 0x56 0x78
左移右移
- 左移操作:将bit位向左移动k位,丢弃高位,低位用0补齐。
- 右移操作:分为算数右移和逻辑右移。
- 逻辑右移是将高位用0补齐。
- 算术右移是将高位用最高位的数补齐。如二进制串 10001010 右移2位,算术右移结果为:11100010。因为最高位为1,所以用1补齐。如果最高位是0,则用0补齐。这种方式对有符号数特别重要。
- Java中,x>>k是算术右移。x>>>k是逻辑右移。
整数的表示
- 无符号整数:字节的每一位都作为整数数值的一部分。
- 有符号整数:用补码编码。最高位的权重是-1,例如1001,表示-1x2^3 + 1 = -7。
- 假如k位有符号整数,则取值范围为:最高位为1,其他位为0,此为最小值。最高位为0,其他位全为1,表示最大值。
- 即 [-2^(k-1), 2^(k-1) -1]。如4位的范围为:[-8,7]
- 在C语言中,将有符号整数转化成无符号整数的时候,如果长度允许,各个位都将保留,所以一个负数最后会变成一个很大正数。
整数的加法
- 无符号整数加法:直接相加,丢掉溢出位。w位二进制数,加法相当于 (a+b)%2^w
- 有符号整数(补码)加法:形式上和无符号整数加法一样。相加结果正溢出,可以表示为(a+b)-2w。结果负溢出,可以表示为(a+b)+2w。
- 判断正溢出:a>0,b>0,结果s<=0。
- 判断负溢出:a<0,b<0,结果s>=0。
- 补码的非,x大于最小值的时候,非即-x。如果x是最小值,则非是x。因为x+x = -2^(w-1) + -2^(w-1) = -2w,导致负溢出,x+x=-2w + 2^w=0。所以最小值是自己的加法的逆。
整数的乘法
- 无符号整数乘法:(a*b)%2^w。即取结果的后w为,溢出的位直接丢弃。
- 有符号整数(补码)乘法:先当做无符号整数相乘,再将结果转成有符号整数即可。即两种乘法的位级表示是一样的,只是最高位的权重相反。