深入理解计算机系统第二版家庭作业答案.docx

上传人:b****8 文档编号:28394965 上传时间:2023-07-13 格式:DOCX 页数:55 大小:44.77KB
下载 相关 举报
深入理解计算机系统第二版家庭作业答案.docx_第1页
第1页 / 共55页
深入理解计算机系统第二版家庭作业答案.docx_第2页
第2页 / 共55页
深入理解计算机系统第二版家庭作业答案.docx_第3页
第3页 / 共55页
深入理解计算机系统第二版家庭作业答案.docx_第4页
第4页 / 共55页
深入理解计算机系统第二版家庭作业答案.docx_第5页
第5页 / 共55页
点击查看更多>>
下载资源
资源描述

深入理解计算机系统第二版家庭作业答案.docx

《深入理解计算机系统第二版家庭作业答案.docx》由会员分享,可在线阅读,更多相关《深入理解计算机系统第二版家庭作业答案.docx(55页珍藏版)》请在冰豆网上搜索。

深入理解计算机系统第二版家庭作业答案.docx

深入理解计算机系统第二版家庭作业答案

深入理解计算机系统(第二版)家庭作业第二章

intis_little_endian(){

inta=1;

return*((char*)&a);

}

(x&0xFF)|(y&~0xFF)

unsignedreplace_byte(unsignedx,unsignedcharb,inti)

{

return(x&~(0xFF<<(i<<3)))|(b<<(i<<3));

}

A.!

~x

B.!

x

C.!

~(x>>((sizeof(int)-1)<<3))

D.!

(x&0xFF)

注意,英文版中C是最低字节,D是最高字节。

中文版恰好反过来了。

这里是按中文版来做的。

这里我感觉应该是英文版对的,int_shifts_are_arithmetic()

intint_shifts_are_arithmetic(){

intx=-1;

return(x>>1)==-1;

}

对于sra,主要的工作是将xrsl的第w-k-1位扩展到前面的高位。

这个可以利用取反加1来实现,不过这里的加1是加1<<(w-k-1)。

如果x的第w-k-1位为0,取反加1后,前面位全为0,如果为1,取反加1后就全是1。

最后再使用相应的掩码得到结果。

对于srl,注意工作就是将前面的高位清0,即xsra&(1<<(w-k)-1)。

额外注意k==0时,不能使用1<<(w-k),于是改用2<<(w-k-1)。

intsra(intx,intk){

intxsrl=(unsigned)x>>k;

intw=sizeof(int)<<3;

unsignedz=1<<(w-k-1);

unsignedmask=z-1;

unsignedright=mask&xsrl;

unsignedleft=~mask&(~(z&xsrl)+z);

returnleft|right;

}

intsrl(unsignedx,intk){

intxsra=(int)x>>k;

intw=sizeof(int)*8;

unsignedz=2<<(w-k-1);

return(z-1)&xsra;

}

intany_even_one(unsignedx){

return!

!

(x&());

}

inteven_ones(unsignedx){

x^=(x>>16);

x^=(x>>8);

x^=(x>>4);

x^=(x>>2);

x^=(x>>1);

return!

(x&1);

}

x的每个位进行异或,如果为0就说明是偶数个1,如果为1就是奇数个1。

那么可以想到折半缩小规模。

最后一句也可以是return(x^1)&1

intleftmost_one(unsignedx){

x|=(x>>1);

x|=(x>>2);

x|=(x>>4);

x|=(x>>8);

x|=(x>>16);

returnx^(x>>1);

}

位机器上没有定义移位32次。

变为2<<31。

C.定义a=1<<15;a<<=15;set_msb=a<<1;beyond_msb=a<<2;

感觉中文版有点问题,注释和函数有点对应不上,于是用英文版的了。

个人猜想应该是让x的最低n位变1。

intlower_one_mask(intn){

return(2<<(n-1))-1;

}

unsignedrotate_right(unsignedx,intn){

intw=sizeof(unsigned)*8;

return(x>>n)|(x<<(w-n-1)<<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。

intfits_bits(intx,intn){

x>>=(n-1);

return!

x||!

(~x);

}

A.得到的结果是unsigned,而并非扩展为signed的结果。

B.使用int,将待抽取字节左移到最高字节,再右移到最低字节即可。

intxbyte(unsignedword,intbytenum){

intret=word<<((3-bytenum)<<3);

returnret>>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就是负溢出。

于是,可以利用三个变量来表示是正溢出,负溢出还是无溢出。

intsaturating_add(intx,inty){

intw=sizeof(int)<<3;

intt=x+y;

intans=x+y;

x>>=(w-1);

y>>=(w-1);

t>>=(w-1);

intpos_ovf=~x&~y&t;

intneg_ovf=x&y&~t;

intnovf=~(pos_ovf|neg_ovf);

return(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>=0时才算溢出。

不过,上述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同号即可判定为溢出。

inttsub_ovf(intx,inty){

intw=sizeof(int)<<3;

intt=x-y;

x>>=(w-1);

y>>=(w-1);

t>>=(w-1);

return(x!

=y)&&(y==t);

}

顺便整理一下汇编中CF,OF的设定规则(个人总结,如有不对之处,欢迎指正)。

t=a+b;

CF:

(unsignedt)<(unsigneda)进位标志

OF:

(a<0==b<0)&&(t<0!

=a<0)

t=a-b;

CF:

(a<0&&b>=0)||((a<0==b<0)&&t<0)退位标志

OF:

(a<0!

=b<0)&&(b<0==t<0)

汇编中,无符号和有符号运算对条件码(标志位)的设定应该是相同的,但是对于无符号比较和有符号比较,其返回值是根据不同的标志位进行的。

根据2-18,不难推导,(x'*y')_h=(x*y)_h+x(w-1)*y+y(w-1)*x。

unsignedunsigned_high_prod(unsignedx,unsignedy){

intw=sizeof(int)<<3;

returnsigned_high_prod(x,y)+(x>>(w-1))*y+x*(y>>(w-1));

}

当然,这里用了乘法,不属于整数位级编码规则,聪明的办法是使用int进行移位,并使用与运算。

即((int)x>>(w-1))&y和((int)y>>(w-1))&x。

注:

不使用longlong来实现signed_high_prod(intx,inty)是一件比较复杂的工作,而且我不会只使用整数位级编码规则来实现,因为需要使用循环和条件判断。

下面的代码是计算两个整数相乘得到的高位和低位。

intuadd_ok(unsignedx,unsignedy){

returnx+y>=x;

}

voidsigned_prod_result(intx,inty,int&h,int &l){

    intw=sizeof(int)<<3;

h=0;

l=(y&1)x:

0;

for(inti=1;i

if((y>>i)&1){

h+=(unsigned)x>>(w-i);

if(!

uadd_ok(l,x<

l+=(x<

}

}

h=h+((x>>(w-1))*y)+((y>>(w-1))*x);

}

最后一步计算之前的h即为unsigned相乘得到的高位。

sign_h=unsign_h-((x>>(w-1))&y)-((y>>(w-1))&x);

sign_h=unsign_h+((x>>(w-1))*y)+((y>>(w-1))*x);

A.K=5:

(x<<2)+x

B.K=9:

(x<<3)+x

C.K=30:

(x<<5)-(x<<1)

D.K=-56:

(x<<3)-(x<<6)

先计算x>>k,再考虑舍入。

舍入的条件是x<0&&x的最后k位不为0。

intdivide_power2(intx,intk){

intans=x>>k;

intw=sizeof(int)<<3;

ans+=(x>>(w-1))&&(x&((1<

returnans;

}

这相当于计算((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<0&&((x<<2)+x的后三位不全为0)。

满足舍入条件的话,结果再加1。

容易证明,加法后三位不全为0可以等价为x后三位不全为0。

intmul5div8(intx){

intb0=x&1,b2=(x>>2)&1;

intans=(x>>3)+(x>>1);

intw=sizeof(int)<<3;

    ans += (b0&b2);

    ans += ((x>>(w-1))&&(x&7));

returnans;

}

不懂题意,感觉就是。

A.1[w-n]0[n]:

~((1<

B.0[w-n-m]1[n]0[m]:

((1<

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)||

(!

sx&&!

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

0

-62

--

最小的值>1

0x3F01

257/256

0

257*2^(-8)

256

0x4700

1

8

--

最大的非规格化数

0x00FF

255/256

-62

255*2^(-70)

-inf

0xFF00

--

--

--

Hex为0x3AA0

0x3AA0

416/256

-5

416*2^(-13)=13*2^(-8)

格式A

格式B

101110001

-9/16

101100010

-9/16

010110101

208

011101010

208

100111110

-7/1024

100000111

-7/1024

000000101

6/2^17

000000000

0

111011000

-4096

111110000

-inf

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]。

floatfpwr2(intx)

{

/*Resultexponentandfraction*/

unsignedexp,frac;

unsignedu;

if(x<-149){

/*Toosmall.Return*/

exp=0;

frac=0;

}elseif(x<-126){

/*Denormalizedresult*/

exp=0;

frac=1<<(x+149);

}elseif(x<128){

/*Normalizedresult.*/

exp=x+127;

frac=0;

}else{

/*Toobig.Return+oo*/

exp=255;

frac=0;

}

/*Packexpandfracinto32bits*/

u=exp<<23|frac;

/*Returnasfloat*/

returnu2f(u);

}

它表示的二进制小数值为:

B.根据,可知1/7的表示为[001]...,

所以22/7为

C.从第9位开始不同。

为了方便测试,我写了几个公共函数。

typedefunsignedfloat_bits;

floatu2f(unsignedx){

return*((float*)&x);

}

unsignedf2u(floatf){

return*((unsigned*)&f);

}

boolis_float_equal(float_bitsf1,floatf2){

returnf2u(f2)==f1;

}

boolis_nan(float_bitsfb){

unsignedsign=fb>>31;

unsignedexp=(fb>>23)&0xFF;

unsignedfrac=fb&0x7FFFFF;

returnexp==0xFF&&frac!

=0;

}

boolis_inf(float_bitsfb){

unsignedsign=fb>>31;

unsignedexp=(fb>>23)&0xFF;

unsignedfrac=fb&0x7FFFFF;

returnexp==0xFF&&frac==0;

}

inttestFun(float_bits(*fun1)(float_bits),float(*fun2)(float)){

unsignedx=0;

do{小数点右移不会到超过30次(否则就越界了),所以exp<=30。

而这里刚好用TMin来表示越界,因此不用关心TMin的表示。

深入理解计算机系统(第二版)家庭作业第三章

intdecode2(intx,inty,intz)

{

intret;

z-=y;

8(%ebp)为result的地址。

12(%ebp)为。

16(%ebp)为。

B.栈中的内容如下表,分配的20个字节用黄底展示(每一行为4个字节)

y

x

返回地址

保存的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+4*edx+8为ap->x[ap->idx]的地址。

ecx存储的是bp(地址)。

ap的地址是bp+4+i*size(A)

我们知道,ap->x[0]的地址是bp+4+i*size(A)+pos(x),pos(x)为结构体A中x的偏移。

那么ap->x[ap->idx]的地址是bp+4+i*size(A)+pos(x)+4*(ap->idx)。

所以4*edx+8=4+i*size(A)+pos(x)+4*(ap->idx)。

所以,不难猜测,pos(x)=4,也就是说,在A中,首先是idx,再是x数组。

那么,我们看ap->idx在哪里计算过。

到第10行,edx的结果是7i+bp[4+28*i],

bp[4+28*i]是什么呢它很可能是bp中的a[i]的首地址。

我们先这样猜测,于是size(A)=28,并且bp[4+28*i]的值为ap->idx。

另一方面:

4*edx=28*i+4*bp[4+28*i]=i*size(A)+4*(ap->idx)。

所以,我们的猜想是正确的。

因此,size(A)=28,里面包含了一个intidx和一个数组intx[6]。

总共有多少个A呢CNT=196/size(A)=7。

A.

:

0

:

4

:

0

:

4

B.

总共需要8个字节。

C.

不难知道,赋值前后都应该是整数。

edx就是参数up(一个指针)。

最后结果是用eax-(edx)得到的,说明(edx)是整数,即up->___为整数,肯定是表示的。

再看看之前的eax,eax是由(eax)所得,说明到第3行后,eax是个指针。

它是由(ecx)得到的,说明ecx在第二行也是个指针。

而ecx是通过*(up+4)得到的,所以ecx是一个union指针next,即up->;

到第三行,eax为*(ecx),且是一个指针,所以eax在第三行为int*p,即up->>。

所以,赋值符号后面的表达式就为*(up->>-up->

再看看前面。

最终赋值的地址是ecx+4,而ecx那时候是一个next指针,而(next+4)必须是一个int,也不难推测它是。

因此前面就为up->>。

结果如下:

voidproc(unionele*up)

{

up->>=*(up->>-up->;

}

版本一:

使用getchar

voidgood_echo()

{

charc;

intx=0;

while(x=getchar(),x!

='\n'&&x!

=EOF)

{

putchar(x);

}

}

版本二:

使用fgets

voidgoo

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 人文社科 > 哲学历史

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1