深入理解计算机系统 家庭作业答案Word格式文档下载.docx
《深入理解计算机系统 家庭作业答案Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《深入理解计算机系统 家庭作业答案Word格式文档下载.docx(63页珍藏版)》请在冰豆网上搜索。
(w-k)-1)。
额外注意k==0时,不能使用1<
(w-k),于是改用2<
sra(int
k){
xsrl=
(unsigned)
x
k;
w=
sizeof(int)<
3;
unsignedz=
1
(w-k-1);
unsignedmask=z
-
unsignedright=mask
xsrl;
unsignedleft=
~mask
(~(z&
xsrl)
+
z);
left
right;
srl(unsignedx,
xsra=
(int)
sizeof(int)*8;
2
(z
xsra;
any_even_one(unsignedx){
!
(0x));
even_ones(unsignedx){
^=
(x>
16);
8);
4);
2);
1);
}
x的每个位进行异或,如果为0就说明是偶数个1,如果为1就是奇数个1。
那么可以想到折半缩小规模。
最后一句也可以是return(x^1)&
1
根据提示想到利用或运算,将最高位的1或到比它低的每一位上,忽然想如果x就是..该如何让每一位都为1。
于是便想到了二进扩展。
先是x右移1位再和原x进行或,变成1100000...,再让结果右移2位和原结果或,变成...,最后到16位,变成...。
leftmost_one(unsignedx){
|=
x^(x>
位机器上没有定义移位32次。
变为2<
31。
C.定义a=1<
15;
a<
=15;
set_msb=a<
beyond_msb=a<
2;
感觉中文版有点问题,注释和函数有点对应不上,于是用英文版的了。
个人猜想应该是让x的最低n位变1。
lower_one_mask(int
n){
(2<
(n-1))
rotate_right(unsignedx,
sizeof(unsigned)*8;
n)
(x<
(w-n-1)<
这一题是看x的值是否在-2^(n-1)到2^(n-1)-1之间。
如果x满足这个条件,则其第n-1位就是符号位。
如果该位为0,则前面的w-n位均为0,如果该位为1,则前面的w-n位均为1。
所以本质是判断,x的高w-n+1位是否为0或者为-1。
fits_bits(int
=
(n-1);
||
(~x);
A.得到的结果是unsigned,而并非扩展为signed的结果。
B.使用int,将待抽取字节左移到最高字节,再右移到最低字节即可。
xbyte(unsignedword,
bytenum){
ret=word
((3
bytenum)<
3);
ret
24;
是无符号整数,因此左边都会先转换为无符号整数,它肯定是大于等于0的。
B.判断条件改为if(maxbytes>
0&
maxbytes>
=sizeof(val))
请先参考题。
可知:
t=a+b时,如果a,b异号(或者存在0),则肯定不会溢出。
如果a,b均大于等于0,则t<
0就是正溢出,如果a,b均小于0,则t>
=0就是负溢出。
于是,可以利用三个变量来表示是正溢出,负溢出还是无溢出。
saturating_add(int
y){
sizeof(int)<
3;
t=x
y;
ans=x
x>
=(w-1);
y>
t>
pos_ovf=
~x&
~y&
t;
neg_ovf=x&
y&
~t;
novf=
~(pos_ovf|neg_ovf);
(pos_ovf&
INT_MAX)
(novf&
ans)
(neg_ovf&
INT_MIN);
对于有符号整数相减,溢出的规则可以总结为:
t=a-b;
如果a,b同号,则肯定不会溢出。
如果a>
=0&
b<
0,则只有当t<
=0时才算溢出。
如果a<
0&
b>
=0,则只有当t>
不过,上述t肯定不会等于0,因为当a,b不同号时:
1)a!
=b,因此a-b不会等于0。
2)a-b<
=abs(a)+abs(b)<
=abs(TMax)+abs(TMin)=(2^w-1)
所以,a,b异号,t,b同号即可判定为溢出。
tsub_ovf(int
=y)&
(y==t);
顺便整理一下汇编中CF,OF的设定规则(个人总结,如有不对之处,欢迎指正)。
t=a+b;
CF:
(unsignedt)<
(unsigneda)进位标志
OF:
(a<
0==b<
0)&
(t<
0!
=a<
0)
t=a-b;
=0)||((a<
t<
0)退位标志
=b<
(b<
0==t<
汇编中,无符号和有符号运算对条件码(标志位)的设定应该是相同的,但是对于无符号比较和有符号比较,其返回值是根据不同的标志位进行的。
详情可以参考第三章节。
根据2-18,不难推导,(x'
*y'
)_h=(x*y)_h+x(w-1)*y+y(w-1)*x。
unsigned_high_prod(unsignedx,
unsignedy){
signed_high_prod(x,
y)
(w-1))*y
x*(y>
(w-1));
当然,这里用了乘法,不属于整数位级编码规则,聪明的办法是使用int进行移位,并使用与运算。
即((int)x>
(w-1))&
y和((int)y>
x。
注:
不使用longlong来实现signed_high_prod(intx,inty)是一件比较复杂的工作,而且我不会只使用整数位级编码规则来实现,因为需要使用循环和条件判断。
下面的代码是计算两个整数相乘得到的高位和低位。
uadd_ok(unsignedx,
y
=x;
void
signed_prod_result(int
y,
h,
l){
h=
0;
l=
(y&
1)?
x:
for(int
i=1;
i<
w;
i++){
if(
(y>
i)&
)
h
+=
(unsigned)x>
(w-i);
if(!
uadd_ok(l,
x<
i))
h++;
l
i);
h=h
((x>
(w-1))*y)
((y>
(w-1))*x);
最后一步计算之前的h即为unsigned相乘得到的高位。
sign_h=unsign_h-((x>
y)-((y>
x);
sign_h=unsign_h+((x>
(w-1))*y)+((y>
(w-1))*x);
A.K=5:
(x<
2)+x
B.K=9:
3)+x
C.K=30:
5)-(x<
1)
D.K=-56:
3)-(x<
6)
先计算x>
k,再考虑舍入。
舍入的条件是x<
0&
x的最后k位不为0。
divide_power2(int
ans=x>
ans
(w-1))
((1<
k)-1));
ans;
这相当于计算((x<
2)+x)>
3,当然,需要考虑x为负数时的舍入。
先看上述表达式,假设x的位模式为[b(w-1),b(w-2),...,b(0)],那么我们需要计算:
[b(w-1),b(w-2),b(w-3),
...
b(0),
0,
0]
+
[b(w-1),b(w-2),...,b
(2),
b
(1),b(0)]
最后需要右移3位。
因此我们可以忽略下方的b
(1),b(0)。
于是就计算(x>
2)+x,再右移一位即是所求答案。
不过考虑到(x>
2)+x可能也会溢出,于是就计算(x>
3)+(x>
1),这个显然是不会溢出的。
再看看b(0)+b
(2)会不会产生进位,如果产生进位,则再加一。
最后考虑负数的舍入。
负数向0舍入的条件是x<
((x<
2)+x的后三位不全为0)。
满足舍入条件的话,结果再加1。
容易证明,加法后三位不全为0可以等价为x后三位不全为0。
mul5div8(int
x){
b0=x&
1,
b2=
2)&
ans=
3)
(b0&
b2);
7));
不懂题意,感觉就是。
A.1[w-n]0[n]:
~((1<
n)-1)
B.0[w-n-m]1[n]0[m]:
((1<
n)-1)<
m
A.false,当x=0,y=TMin时,x>
y,而-y依然是Tmin,所以-x>
-y。
B.true,补码的加减乘和顺序无关(如果是右移,则可能不同)。
C.false,当x=-1,y=1时,~x+~y=0xFFFFFFFE,而~(x+y)==0xFFFFFFFF。
D.true,无符号和有符号数的位级表示是相同的。
E.true,最后一个bit清0,对于偶数是不变的,对于奇数相当于-1,而TMin是偶数,因此该减法不存在溢出情况。
所以左边总是<
=x。
A.令x为无穷序列表示的值,可以得到x*2^k=Y+x。
所以x=Y/(2^k-1)。
B.(a)1/7,(b)9/15=3/5,(c)7/63=1/9
浮点数的一个特点就是,如果大于0,则可以按unsigned位表示的大小排序。
如果小于0则相反。
注意都为0的情况即可。
所以条件是:
((ux<
1)==0&
(uy<
1)==0)||
(!
sx&
sy)||
!
sy&
ux>
=uy)||
(sx&
sy&
ux<
=uy);
A.,5表示为101,因此位数M就是为,小数f为=。
指数部分应该为E=2,所以其指数部分位表示为e=(2^(k-1)-1)+2=2^(k-1)+1。
位表示三个部分分别是s-e-f,为0-10..01-0100..0。
B.能被准确描述的最大奇数,那么其M=..1,故f部分全为1,E应该为n。
当然,这个假设在2^(k-1)>
=n的情况下才能成立。
这时,s=0,e=n+2^(k-1)-1,f=11...1。
值为2^(n+1)-1。
C.最小的规格化数为2^(1-bias)即2^(-2^(k-1)+2),所以其倒数值V为2^(2^(k-1)-2),所以M为,f部分为全0,E=2^(k-1)-2,e部分为2^(k-1)-2+bias=2^k-3,即为11..101。
位表示为0-11..101-00..0。
描述
扩展精度
值
十进制
最小的正非规格化数
2^(-63)*2^(-2^14+2)
最小的正规格化数
2^(-2^14+2)
最大的规格化数
(2^64-1)*2^(2^14-1-63)
+4932
Hex
M
E
V
-0
0x8000
-62
--
最小的值>
0x3F01
257/256
257*2^(-8)
256
0x4700
8
最大的非规格化数
0x00FF
255/256
255*2^(-70)
-inf
0xFF00
Hex为0x3AA0
0x3AA0
416/256
-5
416*2^(-13)=13*2^(-8)
格式A
格式B
位
101110001
-9/16
101100010
010110101
208
011101010
100111110
-7/1024
100000111
000000101
6/2^17
000000000
111011000
-4096
111110000
011000100
768
011110000
inf
没有特别明白转换成最接近的,然后又说向+inf舍入的含义。
按理说,舍入到+inf就是向上舍入,而并不是找到最接近的。
表格中是按最接近的进行舍入,并且如果超出范围则认为是inf。
如果都按+inf进行舍入,那么第四行格式B将是000000001。
A.false,float只能精确表示最高位1和最低位的1的位数之差小于24的整数。
所以当x==TMAX时,用float就无法精确表示,但double是可以精确表示所有32位整数的。
B.false,当x+y越界时,左边不会越界,而右边会越界。
C.true,double可以精确表示所有正负2^53以内的所有整数。
所以三个数相加可以精确表示。
D.false,double无法精确表示2^64以内所有的数,所以该表达式很有可能不会相等。
虽然举例子会比较复杂,但可以考虑比较大的值。
E.false,0/为NaN,(非0)/为正负inf。
同号inf相减为NaN,异号inf相减也为被减数的inf。
float的k=8,n=23。
bias=2^7-1=127。
最小的正非规格化数为2^(1-bias-n)=2^-149。
最小的规格化数为2^(0-bias)*2=2^-126。
最大的规格化数(二的幂)为2^(2^8-2-bias)=2^127。
因此按各种情况把区间分为[TMin,-148][-149,-125][-126,127][128,TMax]。
float
fpwr2(int
x)
/*Resultexponentandfraction*/
unsignedexp,
frac;
unsignedu;
if
-149)
/*Toosmall.Return*/
exp=
frac=
else
-126)
/*Denormalizedresult*/
1<
(x+149);
128)
/*Normalizedresult.*/
exp=x
127;
/*Toobig.Return+oo*/
255;
/*Packexpandfracinto32bits*/
u=exp
23
/*Returnasfloat*/
u2f(u);
的二进制数表示为:
011,E=128-127=1,
它表示的二进制小数值为:
B.根据,可知1/7的表示为[001]...,
所以22/7为[001]...
C.从第9位开始不同。
为了方便测试,我写了几个公共函数。
typedefunsignedfloat_bits;
u2f(unsignedx){
*((float*)&
x);
f2u(float
f){
*((unsigned*)&
f);
bool
is_float_equal(float_bitsf1,
f2){
f2u(f2)
==f1;
is_nan(float_bitsfb){
unsignedsign=fb>
31;
unsignedexp=
(fb>
23)
0xFF;
unsignedfrac=fb&
0x7FFFFF;
exp==
0xFF
frac
is_inf(float_bitsfb){
frac==
testFun(
float_bits(*fun1)(float_bits),
float(*fun2)(float)){
unsignedx=
do{
小数点右移不会到超过30次(否则就越界了),所以exp<
=30。
而这里刚好用TMin来表示越界,因此不用关心TMin的表示。
深入理解计算机系统(第二版)家庭作业第三章
decode2(int
z)
ret;
z
-=y;
8(%ebp)为result的地址。
12(%ebp)为。
16(%ebp)为。
B.栈中的内容如下表,分配的20个字节用黄底展示(每一行为4个字节)
y
返回地址
保存的ebp(也是当前ebp的指向)
s2(word_sum的返回值地址)
在汇编中,没懂word_sum15:
ret$4
以及diff12:
subl$4,%esp的意义何在。
可能是为了清除那个result的返回地址。
C.
传递结构体参数就像正常的传值。
结构体的每一个变量可以看做是单独的参数进行传入。
D.
返回结构体的通用策略:
将返回变量的地址看做第一个参数传入函数。
而不是在函数中分配栈空间给一个临时变量,因为eax确实存不下一个结构体,eax充当返回变量的指针的角色。
B取四的倍数的上整数=8。
8+4+(B*2)取四的倍数的上整数=28。
所以B的可选值为8和7。
2*A*B取四的上整数为44,所以A*B的可选值为21和22。
所以A=3,B=7。
我们用结构体A表示a_struct。
首先,根据第11和12行,可以得到CNT*size(A)=196。
根据13行,知道ecx