注:本节内容为 CS:APP 第三版中文版 P73 的旁注。

内容

偏置技术:对于 $0 \leq k < w$,在执行算数位移时,C表达式 (x+(1<<k)-1)>>k 产生数值 $\lceil x / 2^k \rceil$

理解

我们不妨首先说明这个结论对于正数 (无论是无符号数还是补码数) 的正确性。

首先我们应该思考:在什么情况下我们会需要进行刻意的向上取整?答案是不能整除的时候。

而在算术位移中何时不会被除尽?那只能是位移掉的部分有数的情况,即后 $k$ 位不全为 $0$,如下图:

接下来我们便可以分类讨论。我们希望:

  1. 被除尽时,什么都不做
  2. 在没被除尽时,让 $k+1$ 位加一

可以发现,(x+(1<<k)-1)>>k 完美地符合了我们的需要。+(1<<k) 先帮我们把一加上,然后如果能够除尽,刚好可以帮我们抵消掉加一的效果:

$$
[\cdots {\color{red} (+1)} ~~ 0 \cdots 0] - 1 = [\cdots (+0) ~~ {\color {red} 1 \cdots 1}]
$$

而对于除不尽的情况,因为后 $k$ 位有数,所以影响不到 $k+1$ 位,加一仍然能够生效。

至此,我们已经解释了为什么对于正数有效。

那么对于补码的负数呢?我们同样只需要考虑三点:

  1. 条件:注意到,从补码表示的定义出发,不被除尽的条件是相同的,依旧是后 $k$ 位不全为 $0$
  2. 最终目的:还是由补码的定义,除了最高位的位权是负的,其他位的位权都是正的。所以,「让 $k+1$ 位加一」同样是进行增加,所以是正确的。
  3. 可不可行:可行,因为无符号数加法和补码加法的位级表示相同,所以行为完全一致。

还有一个问题前面被回避了:操作时溢出?对于负数而言,只有在前 $w-k$ 位全为 $1$ 时,才有可能溢出。如果不进行向上取整,最后的结果是 -1,而溢出后的向上取整结果是 0,仍然符合我们的要求。

最后修改:2022 年 02 月 13 日 11 : 50 PM
真的不买杯奶茶嘛....qwq