《深入理解计算机系统》 练习题2.42-2.44

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/anlian523/article/details/83896549

补码除以2的幂

具体讲解在书里。这里直接给几个结论:
1)有符号数即补码数执行的是,算术右移。

2)有变量x和 2 k 2^k (0<=k<w),那么 x &gt; &gt; k x &gt;&gt;k 将产生数值 x / 2 k \lfloor {x/2^k} \rfloor

3)正常来说,除法是向零取整,而不是固定的向下取整。所以为了负数除法有正确的结果,在移位前加偏置。所以,当x为负数时,将执行 ( x + ( 1 &lt; &lt; k ) 1 ) &gt; &gt; k (x + (1&lt;&lt;k)-1) &gt;&gt;k 产生数值 x / 2 k \lceil {x/2^k} \rceil
2 k 2^k 当做y,所以就是 x / y \lceil x/y \rceil = ( x + y 1 ) / y \lfloor (x+y-1)/y \rfloor

关于第3条结论,除了书中给出的证明,这里给出一个直观上的解释:
( x + y 1 ) / y = x y + y 1 y (x+y-1)/y =\frac{x}{y} + \frac{y-1}{y}
假如 x y \frac{x}{y} 现在是一个负的小数,y为4, x y \frac{x}{y} 且可以分解为-3和 1 4 \frac{1}{4} ,本来-2.75向下取整是-3,就不是向零取整了。但这里再加上一个 3 4 \frac{3}{4} ,结果就会变成-2,再向下取整,也是正确的结果-2了。
而且上面的分解过程, 4 \frac{?}{4} 是大于等于 1 4 \frac{1}{4} ,小于等于 4 1 4 \frac{4-1}{4} ,所以肯定能保证正确结果。

2.42原理

当x为非负数时,不加偏置。因为此时的向下取整就是向零取整。
当x为负数时,加偏置。

具体来说,就是得到x的符号位上的值是0还是1,如果是1,那么就要加上偏置 2 4 1 2^{4}-1 即15。

2.42代码

int book_div16(int x)
{
        /* Compute bias to be either 0 (x >= 0) or 15 (x < 0) */
        int bias = (x >> 31) & 0xF;//右移31位后,32位上面都是符号位的值
        //如果为非负数,符号位为0,bias变量为0
        //如果为负数,符号位为1,bias变量为0xF,即15
        return (x + bias) >> 4;
}

如上为原书实现。

2.43

在这里插入图片描述
先看M:
代码等价于x = x * 32 -x = x * 31.所以M为31.
再看N:
7 = 2 3 2^3 -1,最后的右移操作也是右移3位,所以N为 2 3 2^3 即8.

2.44

int x = foo();
int y = bar();
unsigned ux = x;
unsigned uy = y;
对于以下的各表达式,回答两个问题:(1)对于任意的x和y值,该表达式是否为true,
(2) 当x和y取什么值时为false

A. (x > 0) || (x-1 < 0)
当x为TMIN时,左边不符合条件,为0;右边负溢出为TMAX,正数不小于0,为0;此时为false

B. (x & 7) != 7 || (x<<29 < 0)
左边要求的是x的低3位不能都为1;右边要求第3位为1(先左移29位,所以有原始的低3位和29位个0组成,此时小于0,说明符号位为1,即原始的低3位的最高那个为1);
低3位分两种情况:
1)除111外的所有情况:左边符合,必返回1,不用管右边。
2)111:左边不符合,但右边符合了,也返回1。
该表达式必为true。

C. (x * x) >= 0
很明显会出现正溢出,但这里和加法的溢出不一样,加法正溢出最多能获得第w+1位的权值 2 w 2^w ,且正溢出结果必为负数。
但这里就不一样了,因为乘积的结果可能很大。正溢出的结果也是可能正,可能负。
规律如下:
将乘积设为s,如果s- 2 w 2^w 为负数,那么s- 2 w 2^w 则为溢出结果。
如果s- 2 w 2^w 为非负数,那么(s- 2 w 2^w )% 2 w 2^w 则为溢出结果。

	short a, b, c;
	a = b = 182;
	c = a * b;

在这里插入图片描述
182*182-65536=33124-65536=-32412

	short a, b, c;
	a = b = 270;
	c = a * b;

在这里插入图片描述
(270*270-65536)%65536=(72900-65536)%65536=7364%65536=7364

	short a, b, c;
	a = b = 400;
	c = a * b;

在这里插入图片描述
(400*400-65536)%65536=(160000-65536)%65536=94464%65536=28928
非要说原因的话,就是加法正溢出会导致第w位的权值为1,而乘积正溢出就不一定了。

D. x<0 || -x <= 0
当x为0时,右边成立;
当x为[1,TMAX],右边必成立;
当x为[TMIN+1,-1],左边成立;
当x为TMIN,左右都成立;
综上,此表达式必为1.

E. x>0 || -x >= 0
当x为0时,右边成立;
当x为[1,TMAX],左边成立;
当x为[TMIN+1,-1],右边成立;
当x为TMIN,左右都不成立;

F. x+y == uy+ux
表达式中含有无符号数,所以左边也会转换为无符号数。等价于unsigned(x+y) == uy+ux.
在二进制上,无符号数和有符号数的加法是一样的,故都为真。
例如:x=y=-1,则ux=uy= 2 32 1 2^{32}-1 (TMAX).
x+y = -2 ,再转无符号明显是 2 32 2 2^{32}-2 (TMAX-1,除最低一位为0外,其余都为1)
x+y = ( 2 32 1 2^{32}-1 )*2 - 2 32 2^{32} = 2 33 2^{33} - 2 - 2 32 2^{32} = 2 32 2 2^{32}-2 .

G. x*~y + uyux == -x
-y = ~y+1,故 ~y=-y-1, 左边= x
(-y-1)+uyux = uyux - xy -x, 不管是无符号数还是有符号数,在二进制层面上相乘后截短后的结果都是相同的。故 uyux-x*y=0, 故结果都为真,道理同上。

参考链接:
[1] https://github.com/haiiiiiyun/book_exercises/blob/master/csapp-v3/chap2/2.43-2.54.txt#L10

猜你喜欢

转载自blog.csdn.net/anlian523/article/details/83896549