第2章 信息的表示和处理

2.2 整数表示

用位来编码整数的两种不同的方式:一种只能表示非负数,另一种可以表示非负数、零和正数

2.2.1 整型数据类型

两条规律:unsigned的最值是signed最值的两倍;
了解signed的相关信息:char:2的8次方;short:2的21次方;int、long是2的43次方。
特别:C和C++都支持有符号(默认)和无符号数,Java只支持有符号数。

2.2.2 无符号数的编码

假设有一个整数数据类型有w位,对于量$\vec{x} = [x_{w-1}, x_{w-2}, \cdots, x_0]$:

$$
B2U_{w}(\vec{x}) \doteq \sum_{i=0}^{w-1} x_i \cdot 2^i
\quad \quad \quad \quad \quad \quad (2.1)
$$

注意,无符号数编码具有唯一性

2.2.3 补码编码

补码编码的定义如下,对于对向量 $\vec{x} = [x_{w-1}, \ x_{w-2}, \ \cdots, \ x_0]$:

$$
B2T_w (\vec{x}) \overset{\underset{\mathrm{def}}{}}{=} -x_{w-1} 2^{w-1} + \sum_{i=0}^{w-2} x_i 2^i \tag{2.3}
$$

注意,补码编码也具有唯一性。

另外,补码编码的范围并不对成,规律为最小值的绝对值等于最大值的绝对值加1。

2.2.4 有符号数和无符号数之间的转换

规律:数值可能改变,但是位模式不变。
规则:如果在最值范围内,可以有相同的无符号和补码表示,而如果超过了这个范围之外,那么对其取最高位处的模。

2.2.5 C语言中的有符号数和无符号数

在C语言中一般是默认为“有符号”的,它们之间的相互转换需要应用函数,对于无符号常量,需要加上后缀字符’u’或者’U’。

2.2.6 扩展一个数字的位表示

如果将一个无符号数转换为更大的数据类型,只需要在开头添加0,也就是”零扩展”。原理如下:
原理:无符号数的零扩展
定义宽度为 $w$ 的位向量 $\vec{u} = [u_{w-1}, \ u_{w-2}, \ \cdots, \ u_0]$ 和宽度为 $w’$ 的位向量 $\vec{u’} = [0, \ \cdots, \ 0, \ u_{w-1}, \ u_{w-2}, \ \cdots, \ u_0]$,其中 $w’ > w$。则 $B2U_w(\vec{u}) = B2U_{w’}(\vec{u’})$。

如果将一个补码数字转换为一个更大的数据类型,可以执行符号扩展,在表示中添加最高有效位的值,原理如下:
原理:补码数的符号扩展
定义宽度为 $w$ 的位向量 $\vec{x} = [x_{w-1}, \ x_{w-2}, \ \cdots, \ x_0]$ 和宽度为 $w’$ 的位向量 $\vec{x’} = [x_{w-1}, \ \cdots, \ x_{w-1}, \ x_{w-2}, \ \cdots, \ x_0]$,其中 $w’ > w$。则 $B2T_w (\vec{x}) = B2T_{w’} (\vec{x’})$。

2.2.7 截断数字

这一点与上述的取模操作类似,对于无符号数的截断,取模即可。原理如下:
原理:截断无符号数
令 $\vec{x}$ 等于位向量 $[x_{w-1}, \ x_{w-2}, \ \cdots, \ x_0]$,而 $\vec{x’}$ 是将其截断为 $k$ 位的结果:$\vec{x’} = [x_{k-1}, \ \cdots, \ x_0]$。令 $x = B2U_w (\vec{x})$,$x’ = B2U_k (\vec{x’})$。则 $x’ = x \mod 2^k$。

补码的截断也是类似的,但需要将最高位转换为符号位:
原理:截断补码数值
令 $\vec{x}$ 等于位向量 $[x_{w-1}, \ x_{w-2}, \ \cdots, \ x_0]$,而 $\vec{x’}$ 是将其截断为 $k$ 位的结果:$\vec{x’} = [x_{k-1}, \ \cdots, \ x_0]$。令 $x = B2U_w (\vec{x})$,$x’ = B2T_k (\vec{x’})$。则 $x’ = U2T_k (x \mod 2^k)$。

2.2.8 关于有符号数和无符号数的建议

有符号数到无符号数的隐式转换,会导致错误或者漏洞。一种方法是绝不是用无符号数。
如果想要把字仅仅看做是位的集合而没有任何数字意义时,无符号数值是非常有用的。