CSAPP DataLab

前言

找到实习之后就一直想着把csapp的lab给补一补,最后也只补了3个左右的lab,后面的cacheLab和mallocLab,可能以后再来了(总共不止5个,值得做的可能是5个哈哈)因为cache那一章讲的是如何优化之类的,而mallocLab讲的是os的内存分配。
介于找到实习后,干劲不够,因此也只艰难地写了前三个lab。
dataLab能让你很好的熟悉数字在计算机中是如何表示的,假如有好好的读过第二章且做过一二星的题,那么应该可以解答大多数的题目。假如答不出的话,可能是你不知道有哪些kill,
本文只写了前13个phase,至于后面几个,网络上有很多可以参考的。

bitXor(int x,int y);

第一题算是蛮简单的,但是比起之前的版本要难一些,多拿纸笔推敲一下就可以解决了。

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

int tmin(void);

好好看书应该能知道tmin就等于Tmax+1也是就是(1<<31)-1+1,送分题

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

int isTmax(int x);

如何判断一个数是Tmax,也就是(1<<31)-1,但是题目不让用<<

最大嘛,也就是31个1,那么我们给他+1,再与其本身进行一个异或操作,就得到了全是1的情况,之后用~判断一波就好了,但是有那么一种情况就-1也会出现这样子的情况,-1本身就是32个1,所以这个时候可以对其本身进行~,也就是说假如是-1,就不能出现也就是!(~x)的情况再或上!~((x+1)|x)

int isTmax(int x) {
  int y=x+1;
  int z=~x;
  y^=x;
  y=!(~y);
  z=!z;
  return (!z)&y;
}

int allOddBits(int x);

直接一个骚操作?AA(10101010)判断一下,或者直接与然后将位数变为2位,再与一次,然后两次!!,两次!!经常用来判断数字是否为0

int allOddBits(int x) {
  int a=(x>>16)&x;
  int b=(a>>8)&a;
  int c=(b>>4)&b;

  return !(c&0xA^0xA);
}

int negate(int x);

送分题,看书就可以了

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

int isAsciiDigit(int x);

判断是否在一个范围内,这是技巧题,也就是说0x30加一个数得是一个负数,0x39加一个数还是正数,0x3A就是负数,利用溢出原理,具体看代码?0x3f+一个数要是一个负数就得那个数字+03f为最大数字+1,0x39加一个数字还是正数就得0x39+一个数字恰好等于最大数字。最后判断符号位就好了。但是这里得要好好运用所给的符号,注意溢出细节

int isAsciiDigit(int x) {
  int a=1<<31;
  int up=~(a|0x39);
  int down=~(a|0x30);
  int upp=(x+up)>>31&1;
  int doo=(x+down+1)>>31&1;
  int ans=(!upp)&(doo);
  return ans;
}
  • 这道题需要注意在计算upp的时候的>>操作符是逻辑左移还是算术移动,后来最后加了一个&就过了,我也不太清楚咋回事,就算是算术左移,最后用(!upp)以及后面的&也还是可以推出来的= =

int conditional(int x,int z);

两次!判断x是否有值,有的话直接(~x+1)

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

int isLessOrEqual(int x,int y);

使用位运算判断大小,分几种情况,位数全相同,符号相同,符号不同,符号不同直接判断符号就好了,相同的话给两者进行一个减法,当需要用到减法的时候,肯定是符号一样的情况,那么对于加法来说,减去一个数就等于加上该数的补,负数的补码等于该数绝对值?(这点没有验证,但是找几个数字演算一下可以成立)两个数字相减法,就可知道谁大谁小了

int isLessOrEqual(int x, int y) {
    int z=!(x^y);
    int a=(x>>31)&1;
    int b=(y>>31)&1;
    int c1=a&(~b);
    int c2=((~a)&b);
    int c3=x;
    x=x+(~y+1);
    x=(x>>31)&1;
    return z|c1|(!c2)&x;
}

int logicalNeg(int x);

模拟取反,先判断有没有位是1,然后再通过一些操作解决。。。

int logicalNeg(int x) {
        int y=x>>16|x;
        int z=y>>8|y;
        int l=z>>4|z;
        int m=l>>2|l;
        int n=m>>1|m;
        n=n&1;
        return n^1;
}

int howManyBits(int x);

问有多少位可以表示该数的有符号形式

int howManyBits(int x) {
  int flag=x>>31;
  int b16,b8,b4,b2,b1;
  x=(~flag&x)|(flag&~x);//1.positive 2.negative
  b16=(!!(x>>16))<<4;
  x>>=b16;
  b8=(!!(x>>8))<<3;
  x>>=b8;
  b4=(!!(x>>4))<<2;
  x>>=b4;
  b2=(!!(x>>2))<<1;
  x>>=b2;
  b1=(!!(x>>1));
  x>>=b1;
  return b16+b8+b4+b2+b1+x+1;
}

unsigned floatScale2(unsigned uf);

这题感觉是用来熟悉浮点数的结构的,课本对乘法运算讲的比较少,so…,不过会这题大概就知道每个结构是干嘛的了

假如是Nan或者无限,也就是阶码为255的时候直接返回原数

假如是非规格的也就是该数字太小,就将尾数直接移动就好了

假如是规格的,就需要将阶码+1,因为阶码代表的是小数点在二进制数的哪里.

unsigned floatScale2(unsigned uf) {
  unsigned sign=uf>>31&1;
  unsigned exp=0xff&(uf>>23);//jiema
  unsigned frac=uf&(0x7fffff);
  unsigned ans;
  if(exp==255)return uf;
  else if(exp==0){
        frac=(frac<<1);
        ans=sign<<31|exp<<23|frac;
  }else {
        exp++;
        ans=sign<<31|exp<<23|frac;
  }
  return ans;
}

int floatFloat2Int(unsigned uf) ;

将浮点数转为int类型,这里得考虑会超出范围的情况,也就是整数部分太大,溢出,所以阶码不能大于31。

之后对其小数点进行一个左右移动的操作,对该浮点数进行调制

正负判断返回




int floatFloat2Int(unsigned uf) {
  int sign=uf>>31&1;
  unsigned exp=(uf>>23)&0xff;
  unsigned frac=uf&0x7fffff;

  int E=exp-(127);
  if(E>=31)return 0x80000000u;
  else if(E<0){return 0;}
  else {
     frac|=(1<<23);
     if(E<=23){
        frac>>=(23-E);
     }else frac<<=(E-23);
     if(sign)frac=-frac;
     return frac;
  }
}

unsigned floatPower2(int x);

pow的浮点数运算,算出规格化数的阶码就好了:x+127

unsigned floatPower2(int x) {
    int E=x+127;
    int INF=0xff<<23;
    unsigned ans=E<<23;
    if(E>=255)return INF;
    else if(E<0)return 0;
    else return ans;
}

后记,这不愧是cmu大一的课程Orz

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值