CSAPP:Lab1 -DataLab

环境准备

最好准备一个纯净的Linux系统,可以通过vmware创建虚拟机,或者使用docker 构建一个centos或者 ubuntu系统。

主机我是windows系统,本机上安装vscode,通过vscode安装remote ssh插件,连接Linux虚拟机,vscode上直接可以打开远程虚拟机中工作区,进行软件开发,比较方便。主要还是csapp的实验需要Linux环境。关于vscode的安装和配置,以及ssh插件安装和配置,大家可以网上搜一下,有很多这方面的教程,如果大家有环境弄不明白的,也欢迎私信我

如下是我搭建的实验环境

实验资料下载

http://csapp.cs.cmu.edu/3e/labs.html 

另外,有兴趣做书中每章节后的homework的,书后homework答案可以参考

https://dreamanddead.github.io/CSAPP-3e-Solutions/chapter2/2.63/

实验开始

实验开始前,先阅读下README文档,我们主要的工作就是编辑bits.c源文件中的各个函数,每次修改完源文件,要通过make btest进行编译,然后通过./dlc -e bits.c来检查源文件的合法性,最后通过运行./btest 检测我们写的函数功能是否通过

如下图,如果函数功能通过,会显示得分,不通过,会给出每个函数的错误信息

 下面是我的代码实现,具体的思路我写在注释里了(一定要按照函数上面的注释要求实现,限定了你的操作和次数)

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) {
  //a^b=(x&~y)|(y&~x)
  //a|b=~(~a&~b)
  int a=x&~y;
  int b=y&~x;
  int c=~(~a&~b);
  return c;
}
2.tmin
/* 
 * tmin - return minimum two's complement integer 
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 4
 *   Rating: 1
 */
int tmin(void) {
  //1000...
  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) {
  int a=!(~x);//排除-1的干扰,若x=-1,此时a=1,经过下面return的逻辑取反,返回0
  return !((~(x+1)^x) | a);
}
 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) {
  //mask=0xAAAAAAAA;//构造一个掩码奇数位为1,偶数位为0,如果参数为真,和掩码and操作会等于掩码值
  //因为只能使用小于等于255的常数,掩码构造需要一个小技巧
  int a=0xAA<<8; //0xAA00
  int c=a|0xAA; //0xAAAA
  int mask=c<<16|c; //0xAAAAAAAA
  return !((x & mask) ^ mask);
}
5.negate 
/* 
 * negate - return -x 
 *   Example: negate(1) = -1.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 5
 *   Rating: 2
 */
int negate(int x) {
  //补码非,等于位编码取反再加1
  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) {
  //a-b=a+(-b)=a+(~b+1)
  //x-0x30>=0 && 0x39-x>=0即可
  int flag1=!((x+(~0x30+1))>>31 & 1);//取符号位的值
  int flag2=!((0x39+(~x+1))>>31 & 1);
  return flag1 & flag2;
}
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) {
  //先逻辑取反后,只有两种情况0或者1,再左移31位获取符号位,然后算数右移扩展成32位掩码
  int mask=((!x) << 31) >> 31;//1111111... or 0000000...
  return (mask & z) | (~mask & y);//两者取其一
}
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) {
  //考虑到会溢出(两个数异号的情况下),不能直接通过y-x进行判断
  //分两种情况,两者同号的情况下,不会溢出,进行相减,此时xor为0,判断相减后的符号(!xor & !signDiff)
  int signx = x>>31 & 1;
  int signy = y>>31 & 1;
  int xor = signx ^ signy;
  int diff = y+(~x + 1);
  int signDiff = diff>>31 & 1;
  return (!xor & !signDiff) | (xor & signx);//两者异号的情况,xor为1,因为判断x<=y,x若为负数,signx为1,y则为正;x为正,signx为0,y为负
  //所以,xor & signx,即可判断两者异号的情况下,x<=y成立的条件
}
 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(其实还有1000…0,但是这种情况没有例外)的补码是自己本身,其他数字的补码都是其相反数,符号位改变。
//  那么如果用原数x与(~x + 0x1)进行按位或,就可以得到符号位为1,对其进行算数右移即可得到全1的位模式,而0的补码是其本身,经过这套操作,结果还是全0的位模式。
// (10000.0的补码也是其本身,但因为其本身符号位就是1,所以 x | (~x + 0x1))后也是全1的位模式,所以这种情况不是例外)。
  int check= x | (~x+1);
  return (check>>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) {
  int b16,b8,b4,b2,b1,b0;
    int flag=x>>31;
    x=(flag&~x)|(~flag&x); //x为非正数则不变 ,x 为负数 则相当于按位取反,正数和负数都变成非负数,即0..1..形式,方便计算最高有效位位置
    //利用二分法求int x的最高位1所在的位置
    b16=!!(x>>16) <<4; //如果高16位不为0,则我们让b16=16
    x>>=b16; //如果高16位不为0 则我们右移动16位 来看高16位的情况
    //下面过程基本类似
    b8=!!(x>>8)<<3;
    x >>= b8;
    b4 = !!(x >> 4) << 2;
    x >>= b4;
    b2 = !!(x >> 2) << 1;
    x >>= b2;
    b1 = !!(x >> 1);
    x >>= b1;
    b0 = x;
  return b0+b1+b2+b4+b8+b16+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) {
//   //float指数部分为8位,小数部分23位,还有最开始的符号位,构造掩码获取其指数部分和符号位
//   //0111 1111 1000 ...(...表示20个0)=0x7f800000,指数8位全为1的掩码
//   int exp =(uf&0x7f800000)>>23;
//   int sign = uf&(1<<31);
//   if(exp==0)  return uf<<1|sign;//0和非规格化最小数乘2后,也不会越界
//   if(exp==255)  return uf;//按题目需求返回参数
//   exp++;//指数部分+1,表示乘2
//   if(exp==255)  return 0x7f800000|sign;//乘2后,变为了无穷大,返回无穷大
//   //0x807fffff,构造掩码,保留符号位和小数部分,然后和指数部分合并
//   return (exp<<23)|(uf&0x807fffff);
// }

unsigned floatScale2(unsigned uf) {
    unsigned exp = (uf&0x7f800000)>>23;
    unsigned sign=uf>>31&0x1;
    unsigned frac=uf&0x7FFFFF;
    unsigned res;
    if(exp==0xFF)return uf;
    else if(exp==0){
        frac <<= 1;//这里小数部分乘2后有可能"溢出"到阶码部分,frac=0x7fffff&uf,
        //frac十六进制第一位是7(0111)溢出后第一位变为1,和阶码部分再合并,也是可行的,这里处理比较巧妙,也自然的从非规格化数变成了规格化数
        res = (sign << 31) | (exp << 23) | frac;
    }
    else{
     exp++;
     res = (sign << 31) | (exp << 23) | frac;
   }
   return res;
}
 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) {
  unsigned exp = (uf&0x7f800000)>>23;
    int sign=uf>>31&0x1;
    unsigned frac=uf&0x7FFFFF;
    int E=exp-127;
    if(E<0)return 0;
    else if(E >= 31){
        return 0x80000000u;
    }
    else{
        frac=frac|1<<23;//规格化小数部分隐含的1合并进来
        if(E<23) {//需要舍入
            frac>>=(23-E);
        }else{
            frac <<= (E - 23);
        }
    }
    if (sign)
        return -frac;
    else
        return frac;
}
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) {
  if(x<-149){//2^-126 * 2^-23 如果小于最小的非规格化数
    return 0;
  }else if(x<-126){//小于最大非规格化数
    //E=1-127=-126
    int shift = 23+(x+126);
    return 1 <<shift;
  }else if(x<=127){//小于最大规格化数
    //x=expr-bias
    int expr=x+127;
    return expr << 23;
  }else{
    return (0xFF)<<23;
  }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值