0%

信息的表示和处理

码制

不同的 码制 即对 位模式 做出不同的解释。

原码 反码 补码
最高位作为符号位 \(-2^{w - 1} - 1\) \(-2^w\)
符号位取反 $2^w - 1 - x $ $2^w - x $

第二行是不同码制对最高位的解释,第三行是已知 x 如何求 -x 的表示

原码

为了区分正数和负数,用最高位当作符号位。这样符合人类的直觉,但对计算机计算很不友好。比如:

计算 \(1 + (-1)\)

  • 原码表示 0001 + 1001
  • 如果是纯加法电路会得到 0001 + 1001 = 1010 (结果为-2),计算有误。

这意味着,如果用原码来表示数字,CPU的计算单元(ALU)必须设计的十分复杂。他必须先判断符号位:

  1. 如果符号相同做加法
  2. 如果符号不相同,比较绝对值的大小,用大的减小的,最后决定结果的符号。

为了解决这一问题,就有了反码

反码

要了解反码,就要了解反码是怎么来的

反码的来源

早在机械计算器时代(比如 17 世纪帕斯卡的加法机),人们就在思考:“怎样把该死的减法变成加法?” 因为制造一个能倒着转、能处理“借位”的齿轮装置,比制造一个只管顺着转、只管“进位”的装置要复杂得多。

比如有个只能处理 0~99 的机器,我们要计算 56 - 13,但是我们不想让其倒着转(减法),我们可以通过让 56 加上 13 的反码 99 - 13 = 86,让机器一直顺着转(加法),即可。最后得到的结果为 \[ 56 + 86 = 142\]

与正确结果有误差,我们只用把进位 1 加上即可 42 + 1 = 43

二进制中的反码

根据上述的故事,我们就可以定义反码了:

\[-x_反 = 2^w - 1 - x_反\] 即用 11111...11 - x,这在电路中非常容易实现,只需用一个 反相器(NOT GATE) 即可。

根据这个定义,我们就可以推导出最高位的数值为 \(2^{w-1} - 1\)

处理溢出

计算 \(A - B\)

  1. A > B \[ \begin{aligned} A + (2^w - 1 - B) &= 2^w + (A - B - 1) \\ &= A - B - 1 \end{aligned} \] 最后得到的结果比实际的结果少1

  2. A < B \[ \begin{aligned} A + (2^w - 1 - B) &= 2^w - 1 - (B - A) \end{aligned} \] 最后得到B - A的反码表示,与结果符合(因为B - A的反码的值就是-(B - A) = A - B)

补码

为了解决反码中溢出的问题,我们定义:

\[ -x_补 = 2^w - x_补\]

通过该定义也可以推导出,补码最高位的数值为\(-2^{w-1}\)

补码与反码的关系

\[ -x_补 = -x_反 + 1 \]

推导如下:

\[ \begin{aligned} -x_补 &= 2^w - x_补 \\ &= (2^w - 1 - x_补) + 1 \\ &= -x_反 + 1 \end{aligned} \]

有符号和无符号之间的转化

x 为一个位向量,其位模式可以表示为 \([x_{w - 1}, x_{w - 2}, x_{w - 3} ... , x_0]\)

定义如下函数:

B2U(x) = \(\sum_{i=0}^{w-1}2^{i}x_i\)

B2T(x) = \(-x_{w-1}2^{w-1} + \sum_{i=0}^{w-2}2^{i}x_i\)

根据以上定义,我们可以得到同一个 位模式 ,不同的解释方式(补码或者无符号)得到的值有如下的关系:

\[ \begin{aligned} B2U(x) - B2T(x) &= x_{w-1}2^{w} \\ B2T(x) &= B2U(x) - x_{w-1}2^{w}\\ \end{aligned} \]

整数运算

无符号加法和补码加法

计算中用同一个加法器去处理无符号加法和补码加法

x 和 y: 都为位宽为 w 的位向量。

\(x_{u}、y_{u}、x_{s}、y_{s}\)x和y的无符号和补码表示。

因为我们限制了结果只能用 w 位表示,所以值上有如下关系:

无符号加法: \[ x_{u} + y_{u} = (x_{u} + y_{u})(mod\ 2^w) \]

补码加法: \[ \begin{aligned} x_{t} + y_{t} = U2T(x_{u} + y_{u}) \end{aligned} \]

具体溢出等情况可以参考CSAPP中的内容(P60)