Skip to content

Commit

Permalink
Update "整数表示"
Browse files Browse the repository at this point in the history
  • Loading branch information
moralok committed Apr 24, 2024
1 parent b11e6fe commit bee2624
Showing 1 changed file with 128 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ C语言标准定义了每种数据类型必须**能够表示的最小的取值
**原理**:无符号数编码的定义

$$
B2U_{w}\left(\vec{x}\right) \dot{=} \sum_{i=0}^{w-1}x_{i}2^i
B2U_{w}\left(\vec{x}\right) \dot{=} \sum_{i=0}^{w-1}x_{i}2^i \tag{2.1}
$$

映射的范围
Expand All @@ -182,10 +182,12 @@ $$

函数 $B2U_{w}$ 是一个双射。

### 补码编码

**原理**:补码编码的定义

$$
B2T_{w}\left(\vec{x}\right) \dot{=} -x_{w-1}2^{w-1} + \sum_{i=0}^{w-2}x_{i}2^i
B2T_{w}\left(\vec{x}\right) \dot{=} -x_{w-1}2^{w-1} + \sum_{i=0}^{w-2}x_{i}2^i \tag{2.3}
$$

最高有效位 $x_{w-1}$ 称为符号位,权重为 $-2^{w-1}$,符号位被设置为 1 时,表示值为负,当设置为 0 时,值为非负。
Expand Down Expand Up @@ -243,6 +245,130 @@ $$

> 了解术语来源比单纯的记忆术语有意思多了!
### 有符号数和无符号数之间的转化

C语言允许在各种不同的数字数据类型之间做强制类型转换。
- 从数学的角度来说:
1. 对于两种形式都能表示的值,保持不变
2. 负数转换为无符号数,0
3. 无符号数超过补码范围,TMax
- 从C语言的实现角度来说:**保持位模式不变,改变解释的方式**

**原理**:补码转换为无符号数

$$
T2U_w\left(x\right)\dot{=}B2U_w\left(T2B_w\left(x\right)\right)
$$

对满足 $TMin_w \leq x \leq TMax_w$ 的 $x$ 有:

$$
T2U_w\left(x\right) = \begin{cases}
x & \text{if } x \geq 0 \\\\
x + 2^w & \text{if } x < 0
\end{cases} \tag{2.5}
$$

这是通过比较公式 2.1 和公式 2.3 推导而来

$$
B2U_w\left(T2B_w\left(x\right)\right) = T2U_w\left(x\right) = x + x_{w-1}2^w \tag{2.6}
$$

**原理**:无符号数转换为补码

$$
U2T_w\left(x\right)\dot{=}B2T_w\left(U2B_w\left(x\right)\right)
$$

对满足 $0 \leq u \leq UMax_w$ 的 $u$ 有:

$$
U2T_w\left(u\right) = \begin{cases}
u & \text{if } x \leq TMax_w \\\\
u - 2^w & \text{if } x > TMax_w
\end{cases} \tag{2.7}
$$

这是通过比较公式(2.1)和公式(2.3)推导而来

$$
B2T_w\left(U2B_w\left(u\right)\right) = U2T_w\left(u\right) = u - u_{w-1}2^w \tag{2.8}
$$

### C语言中的有符号数与无符号数

尽管C语言标准没有指定有符号数要采用某种表示,但是几乎所有的机器都使用补码。
通常,大多数数字都默认是有符号的,如果要创建一个无符号常量,必须加上后缀 U 或者 u。
尽管C语言标准没有精确规定应如何进行无符号数和有符号数之间的转换,但大多数系统遵循的原则是底层的位表示保持不变。

> 转换的结果依赖于如何进行转换的规则,要理解胜出的规则的底层逻辑。它避免了计算和修改位模式,只改变了 interpretation。
- 显示的强制类型转换
- **隐式的类型转换**(比如赋值,另外当心发生在**表达式**中的非直观情况)

### 扩展一个数字的位表示

将一个无符号数转换为一个更大的数据类型,只要简单地在表示的开头添加0。这种运算被称为**零扩展**(zero extension)

**原理**:无符号数的零扩展

定义宽度为 $w$ 的位向量 $\vec{u}=\left[u_{w-1},u_{w-2},...,u_0\right]$ 和宽度为 $w'$ 的位向量 $\vec{u}'=\left[0,...,0,u_{w-1},u_{w-2},...,u_0\right]$,其中 $w'>w$。则 $B2T_w\left(\vec{u}\right)=B2T_{w'}\left(\vec{u}'\right)$

按照公式(2.1),该原理直接遵循无符号数编码的定义。

将一个补码数字转换为一个更大的数据类型,可移植性**符号扩展**(sign extension),在表示的开头添加最高有效位的值。

**原理**:补码数的符号扩展

定义宽度为 $w$ 的位向量 $\vec{x}=\left[x_{w-1},x_{w-2},...,x_0\right]$ 和宽度为 $w'$ 的位向量 $\vec{x}'=\left[x_{w-1},...,x_{w-1},x_{w-1},x_{w-2},...,x_0\right]$,其中 $x'>x$。则 $B2T_w\left(\vec{x}\right)=B2T_{x'}\left(\vec{x}'\right)$

根据归纳法,结合公式(2.3)

$$
B2T_{w+1}\left(\left[x_{w-1},x_{w-1},x_{w-2},...,x_0\right]\right)=B2T_{w}\left(\left[x_{w-1},x_{w-2},...,x_0\right]\right)
$$

> 本质上,权重总和的变化量为 0。
### 截断数字

当把int类型的x强制类型转换为short时,就将32位的int截断为16位的short。截断一个数字可能会改变它的值——**溢出的一种形式**

**原理**:截断无符号数

令 $\vec{x}$ 等于位向量 $\left[x_{w-1},x_{w-2},...,x_0\right]$,而 $\vec{x}'$ 是将其截断为 $k$ 位的结果:$\vec{x}'=\left[x_{k-1},x_{k-2},...,x_0\right]$。令 $x=B2U_w\left(\vec{x}\right)$,$x'=B2U_w\left(\vec{x'}\right)$。则 $x'=x \quad mod \quad 2^k$。

通过对等式(2.1)应用取模运算可以得到

$$
\begin{align*}
B2U_w\left(\left[x_{w-1},x_{w-2},...x_0\right]\right) \quad mod \quad 2^k &= \left[\sum_{i=0}^{w-1}x_i2^i\right] \quad mod \quad 2^k \\\\
&= B2U_k\left(\left[x_{k-1},x_{k-2},...x_0\right]\right)
\end{align*}
$$

**原理**:截断补码数值

令 $\vec{x}$ 等于位向量 $\left[x_{w-1},x_{w-2},...,x_0\right]$,而 $\vec{x}'$ 是将其截断为 $k$ 位的结果:$\vec{x}'=\left[x_{k-1},x_{k-2},...,x_0\right]$。令 $x=B2U_w\left(\vec{x}\right)$,$x'=B2T_k\left(\vec{x'}\right)$。则 $x'=U2T_k\left(x \quad mod \quad 2^k\right)$。

> 到这一步有一点感觉,自己主动用数学工具描述原理的能力似乎退化了,尽管不难理解。
> 很微妙的一点是,“截取”并不是开辟了一个更小的空间,虽然也涉及修改“被截取”掉的部分,但本质上是在使用时提取了有用的一部分,忽略了剩余部分,这有点像缓冲区的使用方式。
### 关于有符号数与无符号数的建议

有符号数到无符号数的隐式强制类型转换导致了某些非直观的行为。这些非直观的特性经常导致程序错误,并且这种包含隐式强制类型转换的细微差别的错误很难被发现,因为它们是在没有明确指示的情况下发生的。
避免这类错误的一种方法是绝不使用无符号数。实际上,除了C语言很少有语言支持无符号整数。

使用场景:
1. 往一个字中放入描述各种布尔条件的标记(flag)时
2. 作为地址使用
3. 当实现模运算和多精度运算的数学包时,数字是由字的数组来表示的

> 第3种不太理解。

## 参考文章

- 《深入理解计算机系统》

0 comments on commit bee2624

Please sign in to comment.