【CMU 15-213 CSAPP】详解lab1——datalab

前言

终于开始学大名鼎鼎的CSAPP,一开始配环境就把我配得想退坑。。幸亏配好了

lab1真的很难想,实在想不出来就去瞅别人的思路,然后又再嗯造自己的

所有注释(是的, 代码不一定算)都是作者一点一点想一点一点敲出来的喵

环境配置参考:
CSAPP LAB —— 0. 实验环境搭建_何人听我楚狂声 csdn-CSDN博客

代码思路参考:
CSAPP 之 DataLab详解,没有比这更详细的了 - 知乎 (zhihu.com)
cSAPP lab1 datalab - 知乎 (zhihu.com)

完整代码

1. bitXor

/* 
 * bitXor - x^y using only ~ and & 
 *   Example: bitXor(4, 5) = 1
 *   Legal ops: ~ &
 *   Max ops: 14
 *   Rating: 1
 */
int bitXor(int x, int y) {
  // 按位异或 即 (x & y) | (~x & ~y)
  // 由德摩根律
  return (~(x & y)) & (~(~x & ~y)) ;
}

2. tmin

/* 
 * tmin - return minimum two's complement integer 
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 4
 *   Rating: 1
 */
int tmin(void) {
  // int 占 4 bite即 32 bit
  return 1 << 31;
}

3. isTmax

/*
 * isTmax - returns 1 if x is the maximum, two's complement number,
 *     and 0 otherwise 
 *   Legal ops: ! ~ & ^ | +
 *   Max ops: 10
 *   Rating: 1
 */
int isTmax(int x) {
  // 当x = 0111 1111时,令y = ~x = 1000 0000,则有 2y = 0

  // 但是, 令2y = 0,得y = 1000 0000 或 0000 0000
  // 1000 0000对应的x为 0111 1111,0000 0000对应的x为1111 1111
  // 即,当x = 1111 1111 时,y = 0000 0000,也有 2y = 0
  // 因此需要构造条件过滤x = 1111 1111 的情况

  // 令z = !y,当x = 0111 1111时,z = 0, 当x = 1111 1111时,z = 1
  // 因此只有当x = 0111 1111时,才有2y + z = 0
  int y = ~x; 
  int z = !y; 
  return !(y + y + z);
}

4. allOddBits

/* 
 * allOddBits - return 1 if all odd-numbered bits in word set to 1
 *   where bits are numbered from 0 (least significant) to 31 (most significant)
 *   Examples allOddBits(0xFFFFFFFD) = 0, allOddBits(0xAAAAAAAA) = 1
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 12
 *   Rating: 2
 */
int allOddBits(int x) {
  // 0x55 = 0101 0101 所有偶数位为1
  // x | 0x55555555 中偶数位全为1,
  // 那么,当且仅当x的奇数位全为1时,结果为0xffffffff
  // 对0xffffffff按位取反得0,再取反得到真
  int temp = 0x55;
  temp = temp + (temp << 8);
  temp = temp + (temp << 16);
  return !~(x | temp);

  // 0x55555555 其实也是 ~(0xAAAAAAAA),按照德摩根律
  // return !(~x & 0xAAAAAAAA);
  // 这种写法也是正确的
}

5. negate

/* 
 * negate - return -x 
 *   Example: negate(1) = -1.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 5
 *   Rating: 2
 */
int negate(int x) {
  // 求负数得操作是取反加一
  // 取反:1111 1111 - x = -1 -x
  // 加一:(-1 - x) + 1 = -x
  return ~x + 1;
}

6. isAsciiDigit

/* 
 * isAsciiDigit - return 1 if 0x30 <= x <= 0x39 (ASCII codes for characters '0' to '9')
 *   Example: isAsciiDigit(0x35) = 1.
 *            isAsciiDigit(0x3a) = 0.
 *            isAsciiDigit(0x05) = 0.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 15
 *   Rating: 3
 */
int isAsciiDigit(int x) {
  // 如果 x >= 0x30 && x <= 0x39
  // 那么 x - 0x30 >= 0, x - 0x39  <= 0

  // x - 0x30 >= 0, x - 0x39 - 1 < 0
  // 又 -0x30 = ~0x30 + 1, -0x39 = ~0x39 + 1
  // 即 (x + ~0x30 + 1) >> 31 = 0, (x + ~0x39) >> 31 = -1  
  // 注意:c语言右移补符号位(坑死我了)
  
  int judgeUpper = (x + ~0x39) >> 31; 
  int judgeLower = (x + ~0x30 + 1) >> 31;
  return !(~judgeUpper | judgeLower); //当且仅当judgeUpper为-1而且judgeLower为0时,返回true
}

7. conditional

/* 
 * conditional - same as x ? y : z 
 *   Example: conditional(2,4,5) = 4
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 16
 *   Rating: 3
 */
int conditional(int x, int y, int z) {
  // 先得到x的布尔值:0或者1:x = !!x
  // 全0或全1会更好处理,全0就是0,全1是-1
  // 取反加一得相反数:x = ~x + 1 

  x = ~(!!x) + 1;
  return (x & y) | (~x & z);  //确实很牛逼
}

8. isLessOrEqual

/* 
 * 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) {
  // 跟isAsciiDigit差不多
  // x <= y 得 x - y <= 0  得 x + ~y < 0 得(x + ~y) >> 31 = -1
  // 当 x 和 y 同号时 两数相减不会出现溢出 异号则会 所以需要判断符号
  int flag = (x ^ y) >> 31; // x y同号时,flag = 00..00 否则为 11..11

  // 当 x 和 y 同号时
  int signEq = !~((x + ~y) >> 31 );  // 满足 x <= y 时 signEq = 1

  // 当 x 和 y 不同号时,y是正数时返回true
  int signNeq = !(y >> 31);           // 满足 x <= y 时 signNeq = 1

  // 当 flag = 00..00,flag & signEq = signEq, ~flag & signNeq = 0, 结果为signEq
  // 当 flag = 11..11,flag & signEq = 0, ~flag & signNeq = signNeq, 结果为signNeq
  return (~flag & signEq) | (flag & signNeq); // 受conditional的启发,很牛逼(再次)
}

9. logicalNeg

/* 
 * logicalNeg - implement the ! operator, using all of 
 *              the legal operators except !
 *   Examples: logicalNeg(3) = 0, logicalNeg(0) = 1
 *   Legal ops: ~ & ^ | + << >>
 *   Max ops: 12
 *   Rating: 4 
 */
int logicalNeg(int x) {

  // 0要变成1,直接加一呗
  // 其他数要变成0,还得跟上述操作兼容qwq
  // 思路:有一个操作能使0变成0,除了0的其他所有数变成-1,得到的结果再加一

  // 当x不为0时, x | -x 符号为一定为1, 再右移31位得到-1
  // 当x为0时, x | -x = 0, 右移31位还是0
  return ((x | (~x + 1)) >> 31) + 1;
}

10. howManyBits

/* howManyBits - return the minimum number of bits required to represent x in
 *             two's complement
 *  Examples: howManyBits(12) = 5
 *            howManyBits(298) = 10
 *            howManyBits(-5) = 4
 *            howManyBits(0)  = 1
 *            howManyBits(-1) = 1
 *            howManyBits(0x80000000) = 32
 *  Legal ops: ! ~ & ^ | + << >>
 *  Max ops: 90
 *  Rating: 4
 */
int howManyBits(int x) {
  // 101 表示 -4+2+1 = -3, 1101表示 -8+4+2+1 = -3, 11101表示 -16+8+4+2+1 = -3
  // 由此可见, 在负数的补码前面加很多位1, 得到的值是一样的, 
  // 同理, 去掉前面重复的1,所表达的值也是一样的
  // 因此, 负数找最高位0就能确定需要多少位就能表达这个数
  // 总之:正数找最高位1,负数找最高位0
  int b_0, b_1, b_2, b_4, b_8, b_16;
  int sign = x >> 31; 
  x = (~sign & x) | (sign & ~x); // 正数负数统一处理, 转化为找x的最高位1

  // 别人的办法真是十分巧妙啊(
  b_16 = !!(x >> 16) << 4;  // b_16 = (高16位有1)? 16 : 0
  x = x >> b_16;            // 高16位有1就继续看高16位, 没有就看后面的
  b_8 = !!(x >> 8) << 3;    // 同理 b_8 = (高8位有1)? 8 : 0
  x = x >> b_8;
  b_4 = !!(x >> 4) << 2;    
  x = x >> b_4;
  b_2 = !!(x >> 2) << 1;    
  x = x >> b_2;
  b_1 = !!(x >> 1);         
  x = x >> b_1;
  b_0 = x;                  

  return 1 + b_0 + b_1 + b_2 + b_4 + b_8 + b_16;  // 1 是符号位
}

11. floatScale2

/* 
 * floatScale2 - 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 floatScale2(unsigned uf) {
  // 单精度浮点数32位 符号位1 指数位8 数值位23

  // 取符号, 铁定用的着
  int filter = 1 << 31;
  int sign = uf & filter ; 
  int val;

  // 先判断传入的值是否为非规格化值, 进行特殊处理
  // 只看指数位:(filter >> 8) ^ filter = 0111 1111 1000 00..
  int exp = (((filter >> 8) ^ filter) & uf) >> 23;   
  if (!exp)
    return (uf << 1) | sign;  // 指数为为0, 可以向指数为1平滑转化, 太绝了
  if (exp == 255)
    return uf;

  ++exp;                      // 指数+1就是把值乘2
  if(exp == 255)
    return ((filter >> 8) ^ filter) | sign; // 判断越界

  // 取数值位
  val = ~(filter >> 8) & uf;
  return sign | (exp << 23) | val;
}

12. floatFloat2Int

/* 
 * floatFloat2Int - Return bit-level equivalent of expression (int) f
 *   for floating point argument f.
 *   Argument is passed as unsigned int, but
 *   it is to be interpreted as the bit-level representation of a
 *   single-precision floating point value.
 *   Anything out of range (including NaN and infinity) should return
 *   0x80000000u.
 *   Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
 *   Max ops: 30
 *   Rating: 4
 */
int floatFloat2Int(unsigned uf) {
  // 同上, 先判断非规格化值
  int filter = 1 << 31;
  // int sign = uf & filter;
  int exp = (((filter >> 8) ^ filter) & uf) >> 23;
  int val, sign;

  exp = exp - 127;  // 添加bias 
  if(exp < 0)
    return 0;
  if(exp > 31)
    return filter;  // 超过int范围的数按要求返回0x800..00u 包括inf和NaN

  val = (~(filter >> 8) & uf) | (1 << 23); // 取数值位, 加上隐藏的1
  // 这里的val已经是1.*** 小数点向右移了23位的结果了, 因此只需要再向右移exp - 23 位
  if(exp > 23)
    val = val << (exp - 23);
  else 
    val = val >> (23 - exp); 

  // 负数用补码表示
  sign = filter & uf;
  if(!sign)
    return val;
  else 
    return ~val + 1;
}

13. floatPower2

/* 
 * floatPower2 - Return bit-level equivalent of the expression 2.0^x
 *   (2.0 raised to the power x) for any 32-bit integer x.
 *
 *   The unsigned value that is returned should have the identical bit
 *   representation as the single-precision floating-point number 2.0^x.
 *   If the result is too small to be represented as a denorm, return
 *   0. If too large, return +INF.
 * 
 *   Legal ops: Any integer/unsigned operations incl. ||, &&. Also if, while 
 *   Max ops: 30 
 *   Rating: 4
 */
unsigned floatPower2(int x) {
  // 求2^x = 1.0 * 2^x, 数值部分为0, 指数部分为x

  // float 不能超过 2^127
  // x过大使超过浮点数表示范围时, 按要求返回inf = 0x7f800000
  // x过小按要求返回0
  if(x > 127)
    return 0x7f800000;
  if(x < -126)
    return 0;
  return ((x + 127) << 23) ; // 注意加上bias = 127
}

运行结果

root@Andrew:/mnt/d/.c/csapp/datalab-handout# ./dlc bits.c
root@Andrew:/mnt/d/.c/csapp/datalab-handout# make clean
rm -f *.o btest fshow ishow *~
root@Andrew:/mnt/d/.c/csapp/datalab-handout# make ./btest
gcc -O -Wall -m32 -lm -o btest bits.c btest.c decl.c tests.c
btest.c: In function ‘test_function’:
btest.c:334:23: warning: ‘arg_test_range’ may be used uninitialized [-Wmaybe-uninitialized]
  334 |     if (arg_test_range[2] < 1)
      |         ~~~~~~~~~~~~~~^~~
btest.c:299:9: note: ‘arg_test_range’ declared here
  299 |     int arg_test_range[3]; /* test range for each argument */
      |         ^~~~~~~~~~~~~~
root@Andrew:/mnt/d/.c/csapp/datalab-handout# ./btest
Score   Rating  Errors  Function
 1      1       0       bitXor
 1      1       0       tmin
 1      1       0       isTmax
 2      2       0       allOddBits
 2      2       0       negate
 3      3       0       isAsciiDigit
 3      3       0       conditional
 3      3       0       isLessOrEqual
 4      4       0       logicalNeg
 4      4       0       howManyBits
 4      4       0       floatScale2
 4      4       0       floatFloat2Int
 4      4       0       floatPower2
Total points: 36/36
  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值