第一部分:Bits、Bytes、Integers
- 本部分了解数字的位级表示、操作数字时对数字其他属性的影响、溢出时我们不能做和期望电脑做的事情。
笔记1:二进制表示浮点数的核心思想:小数点右边的数。权重依次为2的-1次方、-2次、-3。。。
笔记2:对一个非零数运用两次!,会得到1
笔记3:左移都是右边补0,右移则分两种,为什么呢?
因为底层表示为补码,最高位为1,表示负数,为0表示正数,因此如果最高位为1,右移也需要补1,才能确保正确除2
笔记4:如果一个单字节数x左移8,将得到0吗?不,是x,因为实际上为模8。只要观察低位的3个bit位移,忽略所有其他位,所以这就像模8一样
(解释:C语言规定移位指令只需要考虑移位量的低 log2(数据类型长度),相当于:实际位移量mod数据类型长度,即8mod8=0 所以这里的实际位移量为零,等于原数X)
1.1 关于整数编码:无符号数和补码
注:B2U的意思是从比特位模式转化成无符号数的编码表示
思想:将加权位求和,每个比特用2的幂来加权
以下为无符号数和二进制补码的公式(当我们看补码的时候,和无符号数唯一的区别就是这种方法可以表示负数和正数):
-
例子:如果为二进制补码,则10110,为-16+4+2=-10;如果为无符号数字,为16+4+2=22
-
考虑一下,10110区间的极值是多少,无符号数和补码两者是不同的:
无符号数:最小为00000,为0(UMIN);最大为11111,为16+8+4+2+1=31(UMAX)
二进制补码:最小为10000,为-16(TMIN);最大为01111,为8+4+2+1=15(TMAX,2^(n-1)-1)
特征1:一般来说,n位bit数,能得到的最大值就是2
n-1,最小值为-2
(n-1)特征2:像01111这样一连串的1组成的数,每一位相加起来,得到的值将比前一位表示的值少1
还有一个有意思的事,就是当所有的位为1时会发生什么?即11111,这将得到-16+8+4+2+1=-1。所以在这种表示中,根据特性2,所有的位为1的数的结果都是-1
下表是常见的数:
下表可以看到,符号位为1时,B2U和B2T将相差:2
n,这里为2
4=16;
这些数字是唯一的,两个方向都是独一无二的,且适用于任何给定的位模式,所以可以在这两者之间定义一个转换的规则或映射,进行变化:
如11111,此时假设为T,则为-1,调用T2U函数,则能变为31
计算机本身并不知道是否给定了位模式,这是由C使用者来决定的
下图为无符号数和二进制补码的转化例子图:
使用Python或Java则无须考虑这个问题,因为C是少数unsigned是一个明确的数据类型的语言之一,可以直接声明unsigned变量,即为unsigned int\short\long等。
-
公式:
TMIN = -TMAX-1
UMAX = 2*TMAX+1(TMAX左移一位加1即可)
案例1:假设有一个4位的数字,如何在不改变其值的情况下扩展为8位?
基本规则:将符号位复制到左侧来完成,思想就是关注起关键作用的位
如1000,为-8,则复制一位,为11000,为-16+8=-8,复制两位,为-32+16+8=-8。。。同理可得,复制四位,就变成了8位,且值不变。当然,这是补码的情况,若是无符号数,则直接左边补0即可。
案例2:缩短一些东西则会发生什么呢?
如无符号数11011=27, 如果要变为4位,则只能丢弃最高位,变为8+2+1=11,如果变为3位,则为2+1=3
如补码11011=-5, 如果要变为4位,则只能丢弃最高位,变为-8+2+1=-5,如果变为3位,则为2+1=3,可以看到,负数能变成正数,正数也能变为负数
最后,看看十六进制的表示