csapp-datalab 详细解答

题目来自CMU的datalab1,解答为笔者原创。

bitXor

int bitXor(int x, int y) {
  int t1=~(x&y);
  int t2=~((~x)&(~y));
  return t1&t2;
}

利用x位与y和反x、反y位与实现位异或。

tmin

int tmin(void) {
  return (1<<31);
}

返回最小的整形0x800000000。

isTmax

int isTmax(int x) {
    int i=x+1;
    x=x+i;
    x=~x;
    i=!i;
    x=x+i;
    return !x;
}

如果输入的是最大的整形0x40000000,则前三行首先获得二进制全1的整数,然后利用后两行排除0xffffffff。

allOddBits

int allOddBits(int x) {
  int a,b,c;
  a=0xAA;
  b=(a<<8)+a;
  c=(b<<16)+b;
  return !(c^(c&x));
}

首先获得奇数位全部唯一的整形c,然后c与x做位与运算取x的奇数位在和c做位异或,最后取反即可得答案。

negate

int negate(int x) {
  return ~x+1;
}

利用补码的性质取负。

isAsciiDigit

int isAsciiDigit(int x) {
  int co1,co2;
  co1=(~0x7)&x;
  co2=(~0x1)&x;
  return !(co1^0x30)|!(co2^0x38);
  
}

将0-9的ascii码分为0x30-0x37,0x38-0x39两类。分别去掉x的低3位和低1位,并与0x30/0x38分别做异或运算并取反,如果有输出为1的,即说明x在数字0-9范围内。

conditional

int conditional(int x, int y, int z) {
  int w=!x,r;
  w=~w+1;
  r=((y&(~w))+(w&z));
  return r;
}

x等于0或不等于0,分别获得值为1,0的w,然后将y,z分别与w相乘(利用位取反和位与实现)最后输出结果即可得。

isLessOrEqual

int isLessOrEqual(int x, int y) {
  int s1,c1,c2,c3,c4,r,sr,s2;
  s1=(x>>31)&1,s2=(y>>31)&1;	
  c1=s1^s2;//same=0,diff=1
  c2=s1&c1;//x=minus y=pos out=1 outp=1
  c3=!(x^(~x+1));//out1 outp=1
  c4=s2&c1;//out1 outp=0
  r=y+(~x+1);
  sr=(r>>31)&1;//out0 outp=1
  return (c2|c3)&(!c4)|((!sr)&(!c1));
}

c1:判断两者符号是否相同。如果不同输出1,相同输出0。
c2:判断是否x为负,y为正,若是则输出1。
c4:判断是否x为正,y为负,若是则输出1。
c3:判断x是否为0xffffffff。
最后通过位或、为与和取反操作实现:
若c2输出1直接输出1,若c3输出1直接输出0;
若c3输出1直接输出1;
最后判断y-x的符号以判断大小。

logicalNeg

int logicalNeg(int x) {
  int r=(~x+1)^x,s;
  s=(x>>31)&1;
  r=r>>31;
  return (~(r&1))&1&~s;
}

首先利用x和x的补码做位异或判断是否为0(或0xffffffff),然后判断x的符号以排除0xffffffff的可能。

howManyBits

int howManyBits(int x) {
  int sign,t,is0,a,b,c,d,o1,o2,o3,o4,o5,e,f,digit,full,d1,d2,d3;
  sign=(x>>31)&1;
  t=((~x+1)&((~sign)+1))+(x&(~!sign+1));
  is0=(~x+1)^x;is0=!is0;
  a=255;a=(a<<8)+a;
  b=a<<16;
  o1=b&t;o1=!!o1;//out 1 = high 16 digits with num
  c=255<<8;
  d1=(16&(~o1+1));
  c=c<<d1;//test high 8 digits
  o2=c&t;o2=!!o2;//out 1 = high 8 digits with num
  d=240;
  d=d<<d1;
  d2=(8&(~o2+1));
  d=d<<d2;
  o3=d&t;o3=!!o3; //out 1 =high 4 digits with num
  e=12;
  d3=(4&(~o3+1));
  e=e<<(d1+d2+d3);
  o4=e&t;o4=!!o4; //out 1 = high 2 digits with num
  f=2;
  f=f<<d1;
  f=f<<d2;
  f=f<<d3;
  f=f<<(2&(~o4+1));
  o5=f&t;o5=!!o5;
  digit=d1+d2+d3+(2&(~o4+1))+(1&(~o5+1))+2;
  full=t^((1<<digit+~2+1);full=!full;
  return digit+~(full&sign)+~(is0&!sign)+2;
  
}

利用二分法
首先判断x的正负,如果为负,则令x=x的补码。判断x是否为0,是否为0xffffffff,得到is0和x的符号位sign。
判断高十六位是否有1存在 得出逻辑值o1。若有1存在,则将考虑的区间取为高十六位,反之取为低十六位。
然后判断高(八、四、二、一)位是否有1存在,得出逻辑值(o2、o3、o4、o5)。若有1存在,则将考虑的区间取为高(八、四、二、一)位,反之取为低(八、四、二、一)位。
最后将o1,o2,o3,o4,o5乘上16,8,4,2,1相加,加上is0和sign的修正即可得到答案。

floatScale2

unsigned floatScale2(unsigned uf) {
    int m=1<<31;
    unsigned si,exp,expr,frac;
    if(uf==0||uf-m==0)return uf;
    si=uf&m;
    exp=255;
    exp=exp<<23;
    expr=exp&uf;
    if(expr==exp)return uf;
    frac=(~exp)-m;
    frac=frac&uf;
   
    if(expr==0) return(si+(frac<<1));
    //else if(expr==0) return (si+(frac<<1));
    
    else if(frac==0) return ((expr+(1<<23))&~(1<<31))+si;
    else return ((expr+(1<<23)+frac)&~m)+si;  
 }  

首先判断uf是否为0或-0,,若是则返回uf。
然后判断指数部分是否为全1,是则返回uf。
然后判断指数部分是否为0,是则返回小数部分左移一位并加上符号si。
然后判断小数部分是否为0,是则返回指数部分加1在加上符号si。
若都不为零,则返回指数部分加1再加小数部分再加上符号si。

floatFloat2Int

int floatFloat2Int(unsigned uf) {
    int si,ex,exp,frac,fracr,result=0;
    si=uf&(1<<31);
    ex=255<<23;
    exp=((ex&uf)>>23);
    if(exp==0) return 0;
    if(exp==255) return 0x80000000;
    exp=exp-127;
    frac=~ex-(1<<31);
    if(exp>30) return 0x80000000;
    if(exp<0) return 0;
    fracr=frac&uf;
    result=0;
    if(exp>=0)
        result=1<<exp;
    if(exp>23) {
    	result+=fracr<<(exp-23);
    	if(si) return -result;
    	else return result;
    }
    result+=fracr>>(23-exp);
    if(si) return -result;
    else return result;
          
}

首先检测是否超出范围(是否为INF,是否超过int范围,即指数部分超过30)
然后检测是否为非规范数,若是则返回0;
若没有超过范围,则对小数部分左移(指数大于23)exp-23位或右移(指数小于等于23)23-exp位。
最后根据uf的符号返回-result或result。

unsigned floatPower2(int x) {
    int INF=255<<23;
    int exp=x+127;
    if(exp<=0) return 0;
    if(exp>=255) return INF;
    return exp<<23;


令x+127得到指数部分exp。
首先检测exp是否为0,是则直接返回0。
然后检测exp是否溢出,若是则返回INF。
若exp在正常范围,则返回exp<<23。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值