CSAPP 配套实验 DataLab

第一次写博客,当作随笔留给自己看吧,如果能帮到读者,是我的荣幸。
这是 CSAPP 的配套实验 DataLab,概括的来说就是在较严格的限制条件下把 15 个函数补充完整。
本人能力没有那么强,很多题目都是借鉴了(抄袭了= =)网上大佬的做法,当然也有些题目看不懂大佬的做法,但是结合了大佬的思想,自己写了出来。
很多函数的下面都附加了自己的理解。
在 ubuntu 12.04 下测试全部通过
每次修改 bits.c 后的测试顺序
./dlc bits.c 		(检查编码是否符合规则)
make btest		(相当于编译检查语法)
btest bits.c		(测试bits.c所有函数的正确性)

注:./dlc bits.c,检查编码是否符合规则 这一步非常有必要,因为即使你后面测试函数得到了满分,但是不符合编码规则将视作零分
btest 测试单个函数的方法是 btest -f FuncName,其他更多用法请自行参考说明文件
1

/*
 * bitAnd - x&y using only ~ and |
 *   Example: bitAnd(6, 5) = 4
 *   Legal ops: ~ |
 *   Max ops: 8
 *   Rating: 1
 */
int bitAnd(int x, int y) {
   return ~((~x) | (~y));
}
//利用德摩根律

2

/*
 * getByte - Extract byte n from word x
 *   Bytes numbered from 0 (LSB) to 3 (MSB)
 *   Examples: getByte(0x12345678,1) = 0x56
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 6
 *   Rating: 2
 */
int getByte(int x, int n) {
   return ((x >> (n << 3)) & 0xFF);
}
//将所要取的字节移到最右端然后其余位通过与运算置0

3

/*
 * logicalShift - shift x to the right by n, using a logical shift
 *   Can assume that 0 <= n <= 31
 *   Examples: logicalShift(0x87654321,4) = 0x08765432
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 20
 *   Rating: 3
 */
int logicalShift(int x, int n) {
     int tmp = 32 + (~n);
     return (x >> n) & ((1 << tmp) + (~0) + (1 << tmp));
}
//运用机器的算术右移,然后高位置0和低位保持
//右移n位后原最高位到了第31-n位,31-n表示为31+((~n)+1) = 32+(~n)
//通过与高n位全为0,第32-n位全为1的数实现高位置0和低位保持
//这个数是(1 << ((32+(~n)+1)) - 1
//由于n可能为0,这样左移32位会根据gcc编译规则左移 32 % 32(类型位长) = 0位
//故将该数表示为(1 << (32+(~n)+1)) + (~0) + (1 << (32+(~n)+1))

4

/*
 * bitCount - returns count of number of 1's in word
 *   Examples: bitCount(5) = 2, bitCount(7) = 3
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 40
 *   Rating: 4
 */
int bitCount(int x) {
      //造数
     int _tmp1 = 0x55 | (0x55 << 8);  //0x00005555
     int _tmp2 = 0x33 | (0x33 << 8);  //0x00003333
     int _tmp3 = 0xf | (0xf <<8);     //0x00000f0f
     int tmp1 = _tmp1 | (_tmp1 << 16);   //0x55555555
     int tmp2 = _tmp2 | (_tmp2 << 16);   //0x33333333
     int tmp3 = _tmp3 | (_tmp3 << 16);   //0x0f0f0f0f
     int tmp4 = 0xff | (0xff << 16);     //0x00ff00ff
     int tmp5 = 0xff | (0xff << 8);      //0x0000ffff
     //求和
     int res = 0;
     res = (x & tmp1) + ((x >> 1) & tmp1);
     res = (res & tmp2) + ((res >> 2) & tmp2);
     res = (res & tmp3) + ((res >> 4) & tmp3);
     res = (res & tmp4) + ((res >> 8) & tmp4);
     res = (res & tmp5) + ((res >> 16) & tmp5);
     //返回
     return res;
}
//类似递归分治的思想,以统计二进制数x=10中1的个数为例
//方法是将高位移到低位和0x1相与,(x & 0x1) + ((x >> 1) & 0x1)
//造出5个数,0x55555555,0x33333333,0x0f0f0f0f,0x00ff00ff,0x0000ffff
//这五个数写成二进制,分别隔着1,2,4,8,16个0
/*
 * bang - Compute !x without using !
 *   Examples: bang(3) = 0, bang(0) = 1
 *   Legal ops: ~ & ^ | + << >>
 *   Max ops: 12
 *   Rating: 4
 */
int bang(int x) {
     return ((~((x | ((~x)+1)) >> 31)) & 0x1);
}
//将一个非零数的补码与其相反数的补码相或,最高位一定是1
//但如果对0进行此操作,最高位还是0

6

/*
 * tmin - return minimum two's complement integer
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 4
 *   Rating: 1
 */
int tmin(void) {
   return (0x1 << 31);
}
//最小负整数的二进制补码是1000...0000

7

/*
 * fitsBits - return 1 if x can be represented as an
 *  n-bit, two's complement integer.
 *   1 <= n <= 32
 *   Examples: fitsBits(5,3) = 0, fitsBits(-4,3) = 1
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 15
 *   Rating: 2
 */
int fitsBits(int x, int n) {
     return !(((x >> (n+(~0))) + 1) >> 1);
}
//若n位能表示这个数
//正数的1只能出现在低n-1位,其余位全为0
//负数的0只能出现在低n-1位,其余位全为1
//故将该数右移n-1位后所得结果,正数全为0,负数全为1
//此时再+1后右移1位,可以得到全0
//若n位不能表示这个数,则一定不会有以上结论
//n-1表示为n+(-1),即n+(~0)

8

/*
 * divpwr2 - Compute x/(2^n), for 0 <= n <= 30
 *  Round toward zero
 *   Examples: divpwr2(15,1) = 7, divpwr2(-33,4) = -2
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 15
 *   Rating: 2
 */
int divpwr2(int x, int n) {
 return ( x + (((x >> 31) & 0x1) << n) + (~0) + (!((x >> 31) & 0x1)) ) >> n;
}
//本题是对于标准除法/的实现,全正取下整,有负取上整
//而通过移位实现除以2的幂,都是取下整
//故对于负数要加一个偏移量(1 << n) - 1 (证明在深入理解计算机系统第9版P73)
//因为是负数才要加偏移量,所以式子中的1刚好可以用符号位((x >> 31) & 0x1)表示
//若x > 0,(((x >> 31) & 0x1) << n)的结果为0,会导致多减去了1即(~0)
//巧妙多加一个符号位的逻辑非结果即(!((x >> 31) & 0x1)),负数为0,整数为1,恰好弥补

9

/*
 * negate - return -x
 *   Example: negate(1) = -1.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 5
 *   Rating: 2
 */
int negate(int x) {
 return ((~x) + 1);
}
//对一个数的补码进行按位取反加1就能得到其相反数的补码

10

/*
 * isPositive - return 1 if x > 0, return 0 otherwise
 *   Example: isPositive(-1) = 0.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 8
 *   Rating: 3
 */
int isPositive(int x) {
   return !( ((x >> 31) & 0x1) | (!(x << 1)) );
}
//正数和零的符号位为0,负数为1
//左移1位后用!,正数的结果一定为0,负数的结果可0可1,零的结果一定是1
//将以上两个结果相或,正数的结果为0,负数一定为1,零的结果一定是1

11

/*
 * isLessOrEqual - if x <= y  then return 1, else return 0
 *   Example: isLessOrEqual(4,5) = 1.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 24
 *   Rating: 3
 */
int isLessOrEqual(int x, int y) {
 int xSign = (x >> 31) & 0x1;
     int ySign = (y >> 31) & 0x1;
     int signDiff = xSign & (!ySign);
     int signSame = !(((y + (~x+1)) >> 31) & 0x1) & !(xSign ^ ySign);
     return signDiff | signSame;
}
//作差法判断大小
//首先要判断符号位,因为可能存在溢出
    //正数符号位为0,负数符号位为1,列出x,y的真值表
        //x y z
        //0 0 符号相同要进行下一步作差
        //0 1 0(表示x > y)
        //1 0 1(表示x < y)
        //1 1 符号相同要进行下一步作差
    //可以看到若用一个表达式(xSign & !(ySign))可以实现只用第三种情况为1,就可以完成符号位的判断
//接下来还要看其他三种情况,通过与上!(xSign ^ ySign)保证两者同号,因为第二种不同号的情况在该表达式下结果为0,与0就置0
//前面取y-x的符号位,为0说明,y >= x,否则y < x,再取逻辑非配合与操作

12

/*
 * ilog2 - return floor(log base 2 of x), where x > 0
 *   Example: ilog2(16) = 4
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 90
 *   Rating: 4
 */
int ilog2(int x) {
 int res = 0;
   res = res + ((!!(x>>(16 + res)))<<4);
   res = res + ((!!(x>>(8 + res)))<<3);
   res = res + ((!!(x>>(4 + res)))<<2);
   res = res + ((!!(x>>(2 + res)))<<1);
   res = res + ((!!(x>>(1 + res)))<<0);
   return res;
}

13

/*
 * float_neg - Return bit-level equivalent of expression -f for
 *   floating point argument f.
 *   Both the argument and result are passed as unsigned int's, but
 *   they are to be interpreted as the bit-level representations of
 *   single-precision floating point values.
 *   When argument is NaN, return argument.
 *   Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
 *   Max ops: 10
 *   Rating: 2
 */
unsigned float_neg(unsigned uf) {
  unsigned exp = (uf >> 23) & 0xFF;
     unsigned frac = uf & 0x7FFFFF;
 unsigned res = uf ^ 0x80000000;
     if(exp == 0xFF && frac) {
         res = uf;
     }
 return res;
}
//取exp和frac判断是否为NaN
//异或改变符号位

14

/*
 * float_i2f - Return bit-level equivalent of expression (float) x
 *   Result is returned as unsigned int, but
 *   it is to be interpreted as the bit-level representation of a
 *   single-precision floating point values.
 *   Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
 *   Max ops: 30
 *   Rating: 4
 */
unsigned float_i2f(int x) {
 unsigned ans;
 int xSignx = x & (1 << 31);
 int res = 31;
 int ss = 0;
 int ff = 0;
 int tmp;
 if(x == 0) ans = 0;
 else{
  if(xSignx) x = (~x) + 1;
  while(!((1 << res) & x)) {
   res--;
  }
  x = x ^ (1 << res);
  if(res < 23) x = x << (23 - res);
  else {
   tmp = res - 24;
   if(tmp >= 0) ss = (x >> tmp) & 1,ff = ((1 << tmp) - 1) & x;
   x = (x >> (res-23));
  }
  x = x | ((res+127) << 23);
  if(ff == 0) {
   ss = (ss & x);
  }
  x = x + ss;
  x = x | xSignx;
  ans = x;
 }
 return ans;
}

15

/*
 * float_twice - Return bit-level equivalent of expression 2*f for
 *   floating point argument f.
 *   Both the argument and result are passed as unsigned int's, but
 *   they are to be interpreted as the bit-level representation of
 *   single-precision floating point values.
 *   When argument is NaN, return argument
 *   Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
 *   Max ops: 30
 *   Rating: 4
 */
unsigned float_twice(unsigned uf) {
  unsigned tmp = uf;
     unsigned exp = (tmp >> 23) & 0xFF;
     unsigned frac = tmp & 0x007fffff;
     if(exp == 0x0) {   //非规格化数
         tmp =  (tmp & 0x80000000) | (frac << 1);
     }
     else if(exp != 0xFF) {  //规格化数
         tmp += (1 << 23);
         if(((tmp >> 23) & 0xFF) == 0xFF) {
              tmp = tmp >> 23 << 23;
         }
     }
     return tmp;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值