CSAPP实验一DataLab

CSAPP里的实验环境Linux+gcc,首先在虚拟机里安装了Ubuntu,然后分别执行这些命令:

apt-get update								更新apt软件源
sudo apt-get install build-essential		安装C/C++编译环境
sudo apt-get install gcc-multilib			补充gcc完整环境
sudo apt-get install gdb					安装gdb

实验环境就搭建好了。下面是关于第一次实验DataLab的笔记。

  1. bitxor 实现按位异或。
    首先获得x和y都是0或1的位,将这些为置0,其他位置1就是异或了。
    int bitXor(int x, int y) {
      int both_one = x & y;	// 都是1的位
      int both_zero = (~x) & (~y);	// 都是0的位
      return (~both_one) & (~both_zero);	// 其他位置1
    }
    
  2. tmin 返回用补码表示的最小int值。
    补码表示的最小int即10…0。
    int tmin(void) {
      return (1 << 31);
    }
    
  3. isTmax 当x是int的最大值时返回1。
    利用~Tmax == Tmax + 1a ^ a == 0
    int isTmax(int x) {
      // 但是-1也满足此式,因此单独检查该情况
      int minus_one = !~x;	// 只有-1会让minus_one取1,其他数都使其取0
      return !(((~x) ^ (x + 1)) | minus_one);
    }
    
  4. allOddBits 当所有奇数位都是1时返回1,位序号从右向左从0开始。
    先把所有位都取反,然后置所有偶数位为0,如果x是满足条件的数的话此时应该等于0。
    int allOddBits(int x) {
      int mask = 0x55;	// 0101 0101
      // 置所有偶数位为1
      int temp = x | mask;
      mask <<= 8;
      temp |= mask;
      mask <<= 8;
      temp |= mask;
      mask <<= 8;
      temp |= mask;
      // 取反
      return !~temp;
    }
    
  5. negate 返回-x。
    -x在补码的表示就是取反+1。
    int negate(int x) {
      return ~x + 1;
    }
    
  6. isAsciiDigit 当0x30 <= x <= 0x39(即ASCII码的0~9)时返回1。
    满足两个条件:0x30 - x <= 00x39 - x >= 0即可,由于小于等于0时符号位不固定,因此将其转化为判断小于。
    int isAsciiDigit(int x) {
      // 0x30 - x <= 0 -> 0x2F - x < 0
      // 0x39 - x >= 0
      int minus_x = ~x + 1;
      int condition1 = !!((0x2F + minus_x) >> 31);
      int condition2 = !((0x39 + minus_x) >> 31);
      return (condition1 & condition2);
    }
    
  7. conditional 实现x ? y : z
    int conditional(int x, int y, int z) {
      return ((!!x << 31 >> 31) & y) | ((!x << 31 >> 31) & z);
    }
    
  8. isLessOrEqual 当x<=y时返回1。
    当x, y同号时满足y - x >= 0即可,当异号时满足x为负,y为正即可。
    int isLessOrEqual(int x, int y) {
      // 异号
      int xIsNeg = x >> 31;
      int yIsNeg = y >> 31;
      int dif_sign = xIsNeg ^ yIsNeg;	// 异号时为1
      // 同号
      int minus_x = ~x + 1;
      return ((dif_sign & xIsNeg & !yIsNeg) | (!dif_sign & !(y + minus_x >> 31))) & 1;
    }
    
    第一次做的时候只考虑了y - x >= 0的情况,然而若同号,相减可能会溢出。
  9. logicalNeg 实现!运算符。
    除了0以外的任何int值做!运算结果都是1,因此只要找出一种只有0是特殊结果的结果即可。
    x | ~x的符号位总是1,除非x=0。
    int logicalNeg(int x) {
      int minus_x = ~x + 1;
      return ((x | minus_x) >> 31 ) + 1;
    }
    
  10. howManyBits 返回表示x所需的最少位数。
    这题不会做,而且我也不知道题目实例中howManyBits(-1) = 1是为什么,不应该需要2位吗?
  11. floatScale2 实现单精度浮点数*2的操作,下面的几道浮点数题都是对unsigned操作的。
    exp表示8位阶码,frac表示23位尾数。
    当uf是NaN或者无穷大时原样返回即可,当uf是非规格化数时给尾数×2即可,当uf是规格化数时exp+1即可,若此时exp=255,则返回无穷大。
    unsigned floatScale2(unsigned uf) {
      int exp = (uf & 0x7F800000) >> 23;
      int sign = uf & 0x80000000;
      // 无穷大或NaN
      if (exp == 255)
        return uf;
      // 非规格化数
      else if (exp == 0)
        return (uf << 1) | sign;
      // 规格化数
      exp++;
      if (exp == 255)
        return 0x7F800000 | sign;
      return (exp << 23) | (uf & 0x807FFFFF);
    }
    
  12. floatFloat2Int 转int。
    阶码是加过偏移常数127的,尾数有一个默认的1。当指数>31或<0时都会超出表示范围。若转换后符号位改变则说明发生了溢出,只要取其相反数即可。
    int floatFloat2Int(unsigned uf) {
      int exp = (uf & 0x7F800000) >> 23;
      int sign = uf >> 31;
      int frac = uf & 0x007FFFFF;
      int E = exp - 127;
      // M = frac + 1
      int M = frac | 0x00800000;
      
      if (E > 31)
        return 0x80000000;
      else if (E < 0)
        return 0;
      if (E > 23)
        M <<= E - 23;
      else
        M >>= 23 - E;
      // 没溢出
      if (!(M >> 31) ^ sign)
        return M;
      else
        return ~M + 1;
    }
    
  13. floatPower2 实现2的幂操作。
    unsigned floatPower2(int x) {
      int exp = x + 127;
      if (exp >= 255)
        return 0x7F800000;
      else if (exp <= 0)
        return 0;
      else
        return exp << 23;  
    }
    
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值