csapp_datalab

#! https://zhuanlan.zhihu.com/p/661117391

datalab

datalab还是很难的,发出来一是为了方便以后复习,而是为了帮助有需要的同学们。希望看到这篇文章的同学不要直接抄袭,还是要自己思考。

一、实验目的

本实验目的是加强学生对位级运算的理解及熟练使用的能力。

二、报告要求

本报告要求学生把实验中实现的所有函数逐一进行分析说明,写出实现的依据,也就是推理过程,可以是一个简单的数学证明,也可以是代码分析,根据实现中你的想法不同而异。

三、函数分析

  1. bitNor函数

函数要求:

函数名bitNor
参数int , int
功能实现~(x|y)
要求只能使用 ~ 和 & 运算符,将结果返回。

实现分析:
实际上实现了x,y每一位存在1取0,全0取1。而&实现的是每一位全1取1,存在0取0。x,y先取反,再&得到全0取1,存在1取0。

函数实现:

int bitNor(int x, int y) {
  return (~x)&(~y);
}
  1. copyLSB函数

函数要求:

函数名copyLSB
参数int
功能实现set all bits of result to least significant bit of x
要求! ~ & ^ | + << >>

分析:
int是有符号数,最低位左移到最高位,再右移回来。

函数实现:

int copyLSB(int x) {
  return (x<<31)>>31;
}
  1. isEqual函数

函数要求:

函数名isEqual
参数int int
功能实现return 1 if x==y,and 0 otherwise
要求! ~ & ^ | + << >>

分析:
相等的话^得到全0,!后得到1

函数实现:

int isEqual(int x, int y) {
  return !(x^y);
}
  1. bitmask函数

函数要求:

函数名bitmask
参数int int
功能实现generate a mask consisting of all 1’s
要求! ~ & ^ | + << >>

分析:
写写画画发现多位1异或就可以出来,关键是highbit左移的合法性,当highbit=31的时候<<31+1非法操作,不同编译器不同结果,所以要两次左移。

函数实现:

int bitMask(int highbit, int lowbit) {
  int high=(1<<highbit<<1)+(~0);
  int low=(1<<lowbit)+(~0);
  int ans=high^low;
  ans=(~((highbit+((~lowbit)+1))>>31))&ans;
  return ans;
}
  1. bitCount函数

函数要求:

函数名bitCount
参数int
功能实现returns count of number of 1’s in word
要求! ~ & ^ | + << >>

分析:
对于两bit的数来讲,1的数量就等于x&1+x>>1&1。那么一字节中01010101就可以作为一个累加的掩码。00110011作为4位累加的掩码。00001111作为8位累加的掩码。递增到4字节,则是扩大4倍。01010101010101010101010101010101,00110011001100110011001100110011,00001111000011110000111100001111,00000000111111110000000011111111,00000000000000001111111111111111。

喜欢我强而有力的二进制直写吗:)

函数实现:

int bitCount(int x) {
  int mask1=0x55;
  int mask2=0x33;
  int mask3=0x0F; 
  int mask4= (0xFF<<16)|0xFF;//0x00FF00FF;
  int mask5= (0xFF<<8)|0xFF;  //0x0000FFFF;

  mask1=(mask1<<8)|mask1;
  mask1=(mask1<<16)|mask1;//0x55555555
   
  mask2=(mask2<<8)|mask2;
  mask2=(mask2<<16)|mask2; //0x33333333;
  
  mask3=(mask3<<8)|mask3;
  mask3=(mask3<<16)|mask3;//0x0F0F0F0F;
  
  x=(x&mask1)+((x>>1)&mask1);
  x=(x&mask2)+((x>>2)&mask2);
  x=(x&mask3)+((x>>4)&mask3);
  x=(x&mask4)+((x>>8)&mask4);
  x=(x&mask5)+((x>>16)&mask5);

  return x;
}
  1. tmax函数

函数要求:

函数名tmax
参数void
功能实现return maximum two’s complement integer
要求! ~ & ^ | + << >>

分析:
tmax二进制是0后面31个1,1左移到首位再取反即可。

函数实现:

int tmax(void) {
  return ~(1<<31);
}
  1. isNonNegative函数

函数要求:

函数名isNonNegative
参数int
功能实现return1,ifx>=0,return 0 otherwise
要求! ~ & ^ | + << >>

分析:
x>=0时,符号位为0,>>31位高位补0最后得到0,逻辑取反!即可。x<0时,符号位为1,>>31位后得到全1,逻辑取反!得到0。

函数实现:

int isNonNegative(int x) {
  return !(x>>31);
}
  1. addOK函数

函数要求:

函数名addOK
参数int int
功能实现Determine if can compute x+y without overflow
要求! ~ & ^ | + << >>

分析:
正溢出负溢出后3个符号位为001或者110,而不溢出有以下几种情况:101,100,111,000,011,010。而001和110满足一个条件,前两位相同,并且和最后一位不同。在可以使用if的情况下直接判断,而在lab中,就要用其他方法判断:设符号位分别为a,b,c,则只需要返回!(((!(ab))&(ac))&(b^c))。

函数实现:

int addOK(int x, int y) {
  int z=x+y;
  int a=(x>>31)&0x1;
  int b=(y>>31)&0x1;
  int c=(z>>31)&0x1;
  return !(((!(a^b))&(a^c))&(b^c));
}
  1. rempwr2函数

函数要求:

函数名rempwr2
参数int int
功能实现Compute x%(2^n),for 0<=n <=30
要求! ~ & ^ | + << >> Negative arguments should yield negative remainders

分析:
对于正数,最低n位就是答案。负数就是转换成正数再取最低n位再取反就是答案。要进行两次有关符号位的正反转换。又知道全1得到全反,全0得到本身,则有下面的函数。

函数实现:

int rempwr2(int x, int n) {
    int s=x>>31;//x为正数就是全0,x为负数就是全1
    int mask;
    int ans;
    x=(x^s)+(s&0x1);//x为负数的时候就是按位取反+1;
    mask=(1<<n)+(~0);
    ans=((x&mask)^s)+(s&0x1);//同上
    return ans;
}
  1. isLess函数

函数要求:

函数名isLess
参数int int
功能实现if x < y then return 1, else return 0
要求! ~ & ^ | + << >>

分析:
不考虑溢出的情况x < y得到x-y<0。只有负数-正数的情况下会产生溢出,得到正数。不溢出的情况下符号位有001,101,111,溢出符号位是100。 而x>=y时符号位有110,010,000,溢出时011。则在前4种情况下返回1,后4种情况下返回0。观察发现x符号位小于y符号位的时候直接返回1,剩下情况讨论相与。如果不限制ops可以像数字逻辑一样析取合取。

函数实现:

int isLess(int x, int y) {
  int s = ((x&~y)>>31)&1;
  int m = ~((x^y)>>31);
  return s | (((m)&((x+~y+1))>>31)&1);
}
  1. absval函数

函数要求:

函数名absval
参数int
功能实现absolute value of x
要求! ~ & ^ | + << >>

分析:
正数取自己,负数用符号位操作,详细见9.。TMIN得到自己本身,没办法,int表示范围有限。

函数实现:

int absVal(int x) {
  int s=x>>31;
  x=(x^s)+(s&0x01);
  return x;
}
  1. isPower2函数

函数要求:

函数名isPower2
参数int
功能实现returns 1 if x is a power of 2,and 0 otherwise,no negative number is a power of 2.0 is not a power of 2.
要求! ~ & ^ | + << >> ops 20

分析:
正数2的幂的话只有1个1,比如1000,-1得到0111,按位与就是全0,不会有同位出现。负数的话INT_MIN-1得到INT_MAX,按位与也是全0,要特判,直接特判负数。0-1得到全1,按位与也是0,要特判。
函数实现:

int isPower2(int x) {
  return (!(x&(x+(~0))))&(!(x>>31))&((!!(x&x)));
}
  1. float_neg函数

函数要求:

函数名float_neg
参数unsigned
功能实现Return bit-level equivalent of expression -f for floating point argument f
要求Any integer/unsigned operations incl. ||, &&. also if, while Max ops: 10

分析:
float的参数是1,8,23。正负靠最高位判定。如果argument是NaN,即中间8位全1,末尾23位非全0.这个数unsigned大于首位+全1+全0,直接特判。

函数实现:

unsigned float_neg(unsigned uf) {
  unsigned s= uf>>31;
  if(s){
    if(uf>0xFF800000)
    return uf;
    return uf&0x7FFFFFFF;
  }
  else{
    if(uf>0x7F800000)
    return uf;
    return uf|0x80000000;
  }
}
  1. float_half函数

函数要求:

函数名float_half
参数unsigned
功能实现Return bit-level equivalent of expression 0.5*f for floating point argument f
要求Any integer/unsigned operations incl. ||, &&. also if, while Max ops: 30

分析:
规格化的情况下直接E-1,当E=1的时候表示s*1.M*2^(-126),s*0.1M*2^(-125),此时除以2,得到s*0.1M*2^(-126),用S全0(1(M>>1))表示。非规格E全1的时候,直接返回。非规格E全0的时候表示0.M*2^(-126),除以2得到0.0M*2^(-126),用S全0(0(M>>1))表示。

函数实现:

unsigned float_half(unsigned uf) {
  unsigned S=uf>>31;
  unsigned E=(uf>>23)&0xFF;
  unsigned M=uf&0x7FFFFF;
  unsigned s=S<<31;
  unsigned MS=M>>1;
  unsigned m;
  if(E==0x000000FF)
  return uf;
  if ((M&0x3)==3) {
    m = (MS) +1; 
  } else {
    m = MS;
  }
 if (E == 0) {
    return (s) + m;
  }
  if(E==1)
  return (s)+0x00400000+m;
  return (s)+((E-1)<<23)+M;
}
  1. float_i2f函数

函数要求:

函数名float_i2f
参数int
功能实现return bit-level equivalent of expression (float)×,result is returned as unsigned int.
要求Any integer/unsigned operations incl. ||, &&. also if, while Max ops: 30

分析:
如果输入整数为0,直接返回0。如果输入整数为INT_MIN,返回0xCF000000,
处理符号位和无符号整数:首先确定符号位S,然后将输入整数取绝对值并赋给无符号整数ux。
关键在于向右进位舍入,当丢掉的大于一半,或者等于一半且低位为1的时候进,其余直接舍。

函数实现:

unsigned float_i2f (unsigned int x) {
  // 提取符号位
  unsigned int S = x & (1 << 31);
  // 提取指数部分
  unsigned int E = 0;
  // 提取尾数部分
  unsigned int M = 0;
  // 用于四舍五入的临时变量
  unsigned int round = 0;
  // 计算绝对值
  unsigned int Abs = S ? (~x + 1) : x;
  unsigned int temp = Abs;

  // 计算指数
  while ((temp = temp >> 1))
      ++E;
  // 计算尾数,左移保留精度位数
  M = Abs << (31 - E) << 1;
  // 计算四舍五入位
  round = M << 23 >> 23;
  // 移除尾数多余的位数
  M = M >> 9;
  
  // 进行四舍五入
  if (round > 0xFF + 1) 
    round = 1;
  else if (round < 0xFF + 1) 
    round = 0;
  else 
    round = M & 1;
  
  // 构建浮点数表示并返回
  return x ? (S | ((E + 0x7F) << 23) | M) + round : 0;
}
  • 8
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值