CSAPP - LAB 1 datalab

Environment Construction

确保有一个linux系统,并已经执行过以下两条命令:
安装gcc:sudo apt-get install build-essential
安装gcc的交叉编译环境.):sudo apt-get install gcc-multilib,因为实验的程序需要以32位方式编译
CMU的CSAPP网站上下载实验所需资料,包括**README, Writeup,Self-Study Handout,**这三部分均包含对实验的要求说明(Handout的说明在其包含的bits.c文件中由注释给出),Self-Study Handout包括用于测试的文件


Lab1: DataLab

1.bitXor(x,y)

要用~和&实现异或^,即将结果中 1-0,0-1对应的位设置为1
x&y中为1的位(bit)对应 1-1; 取反后为:0-0、0-1、1-0;
(x&y)为1的位(bit)对应 0-0; 取反后为:1-1、0-1、1-0;
两个做交集即为结果。(位向量可以表示集合,&,|,~可视为 交,并,补操作)

/*
bitXor - x^y using only ~ and & 
Example: bitXor(4, 5) = 1
Legal ops: ~ &
Max ops: 14
Rating: 1
*/
int bitXor(int x, int y) {
    return  ~(x&y) & ~(~x&~y) ; // if regardless '+' is illegal:(~x&y) + ((x)&(~y)) or ~((x&y) + ((~x)&(~y)))
}

2.tmin

最简单的一题:000...001 --> 1000...000

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

3.isTmax(x)

这题最开始想到 Tmin的一个性质,即对二进制补码 Tmax关于加法的逆为其本身:Tmax+Tmax = 0;因此利用这个性质写出了!((~x) + (~x)),但测试结果出乎意料,加法溢出导致了未知的行为。
根据 Tmax +1 = Tmin 的性质可以得出 , 100...000 + 011...111 = 111..1111 (-1),可得出!(~x^(x+1))(^可替换为+)
处理特例-1: -1同样会产生结果1,根据 -1+1==0,Tmax+1!=0,进而!(-1+1) !=0!(Tmax+1) ==0.
所以对Tmax, x+(x+1) = x , 对-1,x+(x+1)!=x
x+(x+1) 替换原式中的第一项x,最终得出结果:!(~((x+!(x+1))^(x+1)))

/*
isTmax - returns 1 if x is the maximum, two's complement number,
and 0 otherwise 
egal ops: ! ~ & ^ | +
Max ops: 10
Rating: 1
*/
int isTmax(int x) {
  return !(~((x+!(x+1)) ^ (x+1))) ; 
   // !((~x) + (~x));  it should be right, the operator "!" seem to not work
}

4.allOddBits(x)

这道题没想出来,在x上shift的方式想了一个多小时,总是不能满足所有测试用例,说明在x上shift是行不通的。
用好异或即可解决:构造101...1010,再用该数提取x中的奇数位,最后再与101...1010比较

/* 
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) {
  int allOdd = (0xAA << 24) + (0xAA << 16) + (0xAA << 8) + 0xAA; // 10101010..101
  return ! ((allOdd & x) ^ allOdd);   
}

5.isAsciiDigit(x)

有点难,还是自己做出来了,主要使用了掩码提取x中的指定位,再运用前几题的经验—用异或执行比较操作。
x的最后四位,3bit 与 1,2bit不能同时为1,因而有!((x&mask2)^mask2) + (!((x&mask3)^mask3))),难点在于怎么处理好式中三部分的逻辑关系

/* 
 * 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) {
  int mask1 = 0x3;   // 000...0011
  int mask2 = 0xA;   // 1010
  int mask3 = 0xC;   // 1100
  return  !( ((x>>4)^mask1) | (!((x&mask2)^mask2) + (!((x&mask3)^mask3)) ) );
}

6.conditional

比较简单,主要实现这样一个逻辑:x!=0,返回y;x=0,返回z;
涉及的操作是把x转化为0与1两个值,再把000...0001转化为111...1111

/* 
 * 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) {
  int  judge = !(x ^ 0x0); // x=0 -> judge=1,whereas x!=0 -> judge=0
  judge = (judge << 31)>>31; // 000...000 or 111...111
  return ((~judge)&y) | (judge&z);
}

7.isLessOrEqual(x, y)

可通过减法y-x>=0判断x<=y,由于不存在-符,所以取x关于加法的逆-x,进而变为 x+y
那么这题就涉及加法溢出,需要对x+uw y结果的三种情况的判断(negative overflow , positive overflow),变得复杂起来。
更好的想法是分析式子**y-x**并加入一个conditional操作:如果两者异号(正-负,负-正),那么结果的正负的确定的;如果两者同号(同号相减不可能溢出),则通过与Tmin相与提取符号位。

/* 
 * 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 Tmin = 1<<31; // 100...0000
  int signY = Tmin & y;
  int signX = Tmin & x;
  int judge = (signY ^ signX)<<31; 
  x = (~x)+1;
  return (judge&signX) | (~(judge>>31) & !((y+x)&Tmin)) ; // 
}

8.logicalNeg(x)

这题要求自己实现一个 !逻辑,即输入0返回1,输入N(N!=0)返回0。一开始的出发点是:x=0,返回1;x 位向量存在为1的位,返回0。但是仅靠逻辑运算符无法实现该想法。
于是换了一个想法:先得到x的符号位signX。signx为1,说明x为负数,可以直接得到结果;sign为0,说明x即可能为0也可能为正数,那么就要利用补码加法操作会发生的positive overflow现象,即 Tmax + x ,对任意x>0均会使结果变为负数,符号位由0 -->1。(positive overflow 不同于 negative overflow,并没有产生整数溢出,因此不会导致undefined behavior

/* 
 * logicalNeg - implement the ! operator, using all of 
 *              the legal operators except !
 *   Examples: logicalNeg(3) = 0, logi'calNeg(0) = 1
 *   Legal ops: ~ & ^ | + << >>
 *   Max ops: 12
 *   Rating: 4 
 */
int logicalNeg(int x) {
  int Tmin = 1<<31;
  int Tmax = ~Tmin;
  int signX = ((x&Tmin)>>31) & 0x1;
  return (signX^0x1) & ((((x + Tmax)>>31)&0x1)^0x1);
}

9.howManyBits(x)

这题一开始想的是去除符号位后,找位向量中最左边的1的位置序号,但是我忽略了补码的一个性质:当数的符号位为1时,将数按符号位扩展之后其值不会变,如1101与101表示的是同一个值(-3),因此找到最左边的1并不能得到最短的位数。
要找到能表示负数的最短位数,而又不受符号位拓展的影响,便要找最左边的0,而不是1。为与对正数的操作相统一,做法是把负数按位取反(Such as: 1101 -> 0010)
按二分法逐步缩小范围,找到最左边的1

/* 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 signX = x>>31;
  x = ((~signX) & x) | (signX&(~x));// if x is negative, let sign bit:1-> 0
  
  b16 = (!!(x>>16))<<4; // ensure high 16 bits exist 1 or not
  x=x>>b16;
  b8 = (!!(x>>8))<<3; // ensure high 8 bits 
  x=x>>b8;
  b4 = (!!(x>>4))<<2; // ensure high 4 bits 
  x=x>>b4;  
  b2 = (!!(x>>2))<<1; // ensure high 2 bits 
  x=x>>b2; 
  b1 = !!(x>>1); // ensure 31 bits or not 
  x = x>>b1;
  b0 = x;
  
  return b0+b1+b2+b4+b8+b16+1; // 1: sign bit
}

10.floatScale2(uf)

先对题目做出一点解释:传入一个unsigned类型的参数,但是函数内将它解释为一个浮点数类型,即参数的值不是参数的十进制值,而是其二进制形式表示的浮点数值(M×2E)
整体思路:用掩码分别提取sign,exponent,fraction三部分,再根据exp的值分类讨论
注意点:对normalized,f*2的2是乘在了2E;而对denormalized,是乘在了frac表示的M上,这也是为什么frac = frac <<1,这也使得denormalized能转化到normalized (smoothly)

//float
/* 
 * 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    // revision: NaN or infinity
 *   Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
 *   Max ops: 30
 *   Rating: 4
 */
unsigned floatScale2(unsigned uf) {
  int musk_exp,musk_frac,sign,exp,frac,result;
  musk_exp = 0xFF << 23;
  musk_frac = 0x7FFFFF;
  exp = (uf & musk_exp)>>23;
  frac = uf & musk_frac;
  sign = 0x1<<31 & uf;
  result = 5;
  if(exp == 0xFF  ) // NaN
     result = uf;
  else if(exp == 0x0) // denormalized
  {  
     if(frac == 0x0)
     {
        if(sign)  // -0.0
           result = uf;
        else     // +0.0
           result = 0 ;
     }
     
     else
     {
        frac = frac << 1;
        result = sign+ (exp<<23) + frac;
     }
  }
  
  else if(exp != 0x0 && exp != 0xFF) // normalized
  {
     exp += 1;
     result = sign+ (exp<<23) + frac;
  }
  return result;
}

11.floatFloat2Int(uf)

浮点数类型的这几题比前面的题要轻松很多,大概是因为可用符号和结构比较充足的原因吧。
对题目的解释:返回浮点数f的int型表示,如输入12345.0 (0x4640E400), 正确输出为12345 (0x3039)
注意点:当f的值超过32bit的int类型位向量所能表示的最大值时(2^31-1),即E>31时,属于out of range

/* 
 * 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 musk_exp,musk_frac,exp,frac,sign,E,Bias,result;
  musk_exp = 0xFF << 23;
  musk_frac = 0x7FFFFF;
  exp = (uf & musk_exp)>>23;
  frac = uf & musk_frac;
  sign = 0x1<<31 & uf;
  Bias = 127;
  result = 5;
  if(exp == 0xFF  ) // NaN or infinity
     result = 0x80000000u;
     
  else if(exp == 0x0)
     result = 0;
     
  else if(exp != 0x0 && exp != 0xFF) // normalized
  {
     E = exp -Bias;  // bit_num of fraction
     if(E < 0)
        result = 0;
     else if (E>31)
        result = 0x80000000u;
     else
     {
        frac = frac>>(23-E);
        result = (0x1 << E) + frac ; 
        if(sign == 0x1<<31)
           result = - result;
     }
  }
  
  return result;
}

12.floatPower2(x)

注意点:当2^x超过位向量所能表示的最大值(largest normalized)时,即exp 大于 254(1111 1110),属于too large

/* 
 * 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) {
  int exp,frac,E,Bias,result;
  Bias = 127;
  result = 5;
  E = x;
  if(x<1 && x!=0)
     return 0;

  else if(x >= 0x1 || x == 0)
  {
     frac = 0x0;
     exp = E+Bias;
     if(exp > 254)  // 1111 1110
        {
           exp = 0xFF;
           result = exp <<23+frac;         
        }
     else
        result = (exp<<23) + frac; 
  }    
  
  return result ;
}

Consequence

make
./driver.pl

在这里插入图片描述

### CSAPP DataLab 武汉大学 `subok` 参数教程 #### 关于 CSAPP DataLab 的背景介绍 CSAPP DataLab 是《计算机系统基础》(Computer Systems: A Programmer's Perspective, CSAPP)教材中的一个重要实验部分,旨在通过一系列基于位运算的操作加深学生对底层硬件和数据表示的理解[^1]。 在完成 DataLab 中的任务后,通常需要将解决方案上传到特定的服务器进行验证。这一过程涉及到了一个名为 `subok` 的参数设置问题。以下是关于如何正确配置以及提交的相关说明: #### 配置与使用 `subok` 参数 当准备向官方或者学校指定平台提交代码时,确保命令行工具能够识别并接受额外选项是非常重要的一步。具体来说,在执行如下形式的提交指令前需确认环境变量已正确定义好: ```bash make submit SUBMITTY_URL="http://your-submission-server/" COURSE_ID="csapp-datalab" USER_ID="wuhan-university-student" ``` 其中涉及到的关键点之一就是——是否允许未优化版本也成功递交?这便是由布尔型标志 `subok` 来决定的事情。如果将其设为 true,则即使某些题目未能达到最优解法的要求也能顺利完成整个流程;反之则会阻止不符合标准的结果被接收[^2]。 因此,在实际操作过程中需要注意以下几点事项来保障顺利通过检验环节: - **检查本地测试结果**:利用自带脚本如 `./btest` 对各个实现逐一校验其功能性和效率指标; ```bash make && ./btest -f functionName [-param value ...] ``` - **调整适当编译器警告级别**:有时候看似无害的小错误可能隐藏着逻辑隐患,故建议启用更严格的检测机制以便及时发现潜在缺陷; - **明确了解评分细则**:不同院校可能会依据实际情况定制化评判准则,务必提前查阅清楚后再着手修改源文件内容直至满足预期目标为止[^3]。 最后附上一段简单示例展示如何构造符合规范要求下的基本框架结构供参考学习之用: ```c /* * Example Function Implementation According To Given Constraints. */ int exampleFunction(int input){ int mask = 0xFFFFFFFF; return ((input >> 1) & mask); } ``` #### 注意事项总结 综上所述,为了保证能够在武汉大学或者其他任何采用相同体系架构的教学场景下高效完成相应练习项目,请牢记上述提到的各项要点,并严格按照指导手册上的提示逐步推进各项工作进程即可达成理想效果[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值