csapp实验记录 - Datalab

csapp 实验记录

本记录是csapp配套实验的实验记录

CSAPP Lab 官网 本次实验始于:2021-2-7

Data lab

data lab实验是关于计算机信息的表示,主要涉及到整数,浮点数,以及相关操作的位级表示和操作


题目列表

在这里插入图片描述


题解

bitXor(x,y)

计算 x ^ y,只使用与和取反操纵实现异或操作

代码

int bitXor(int x, int y) {
  int a = x & y;
  int b = ~x & ~y;
  return ~a & ~b;
}

通过与和非操作讲二进制位中相同的部分变为不同的部分,然后取反与,不同的部分变为零,相同的部分位1。则实现了异或的操作



tmin()

求补码最小值

代码

int tmin(void) {
  return 1 << 31;
}

补码最小值就是符号位为1,其余位都为0



isTmax()

判断是否是补码最大值

代码

int isTmax(int x) {
  int a = x + 1;
  x = x ^ a;
  x = ~x;
  a = !a;
  x = x + a;
  return !x;
}

补码最大值是符号位为0,其余为都为1,那么Tmax + 1 则变为符号位为1,其余为为0,只需要和原数异或取反,判断是否全为0则能判断是否为补码最大值,但要注意,如何原数位都为1,那么+1溢出位变为都为0,则异或取反也是全为0的数,那么此时需要排除掉原数位都为1的这种情况(0xffffffff)。4-5行即为排除这种情况。



allOddBits(x)

判断奇数位是否都为1

代码

int allOddBits(int x) {
  int i = 0xAA;
  i = i + (i << 8);
  i = i + (i << 16);
  x = x & i;
  x = x ^ i;
  return !x;
}

使用掩码,构造出奇数位都为1的二进制数,然后将其与原数异或即可



negate(x)

整数取反

代码

int negate(int x) {
  x = ~x;
  x = x + 1;
  return x;
}

取反+1就是整数取反



isAsciiDigit(x)

计算输入值是否是数字 0-9 的 ASCII

代码

int isAsciiDigit(int x) {
  int sign = 0x1 << 31;
  int ub = ~(sign | 0x39);
  int lb = ~0x30;
  ub = (ub + x) >> 31;
  lb = (lb + x + 1) >> 31;
  return !(ub | lb);
}

通过位级运算计算 x 是否在 0x30 - 0x39 范围内就是这个题的解决方案。那如何用位级运算来操作呢?我们可以使用两个数,一个数是加上比0x39大的数后符号由正变负,另一个数是加上比0x30小的值时是负数。这两个数是代码中初始化的 ub 和 lb,然后加法之后获取其符号位判断即可。



conditional(x, y, z)

使用位级运算实现C语言中的 x?y:z三目运算符。

代码

int conditional(int x, int y, int z) {
  x = !!x;
  x = ~x + 1;
  return (x & y) | (~x & z);
}

只需要将x是零和非零转换为全0和全1即可用来求返回的是y还是z。1~2行是将x转换位全0或者全1



isLessOrEqual(int x, int y)

使用位级运算实现小于等于

代码

int isLessOrEqual(int x, int y) {
  int negX = ~x + 1;  // -x
  int signXY = (negX + y) >> 31 & 1;  // y - x
  int sign = 0x1 << 31;
  int signX = (sign & x) >> 31;
  int signY = (sign & y) >> 31;
  int bitXor = (signX ^ signY) >> 31 & 1;
  return ((!bitXor) & (!signXY)) | (bitXor & signX);
}

实现小于等于,先比较符号位,如果符号位相同,则看y-x的值是否大于等于0,符号位不同返回符号为正的


logicalNeg(int x)

使用位级运算实现逻辑非

代码

int logicalNeg(int x) {
  return ((x|(~x+1))>>31)+1;
}

实现逻辑非,只需要看x是否是非零和零,根据补码的相反数(取反+1),如果补码的相反不是0,则原数是非0的,如果相反数为0则原数为0。但是有特例,补码的相反数为本身,但是补码最小值的符号位与其相反数的符号位位或为1,可以归到其它非零整数的符号判断上面。



howManyBits(x)

求值:“一个数用补码表示最少需要几位?”

代码

int howManyBits(int x) {
  int b16,b8,b4,b2,b1,b0;
  int sign = x >> 31;
  x = (sign & ~x) | (~sign & x);//如果x为正则不变,否则按位取反(这样好找最高位为1的,原来是最高位为0的,这样也将符号位去掉了)

  b16 = !!(x >> 16) << 4;//高十六位是否有1
  x = x >> b16;//如果有(至少需要16位),则将原数右移16位
  b8 = !!(x >> 8) << 3;
  x = x >> b8;
  b4 = !!(x >> 4) << 2;
  x = x >> b4;
  b2 = !!(x >> 2) << 1;
  x = x >> b2;
  b1 = !!(x >> 1);
  x = x >> b1;
  b0 = x;
  return b16 + b8 + b4 + b2 + b1 + b0 + 1;
}

如果是一个正数,则需要找到它最高的一位(假设是n)是1的,再加上符号位,结果为n+1;如果是一个负数,则需要知道其最高的一位是0的(例如4位的1101和三位的101补码表示的是一个值:-3,最少需要3位来表示)。



floatScale2(f)

求2乘以一个浮点数

代码

unsigned floatScale2(unsigned uf) {
  int exp = (uf & 0x7f800000) >> 23;
  int sign = uf&(1 << 31);
  if (exp == 0) return uf << 1 | sign;
  if (exp == 255) return uf;
  exp ++;
  if (exp == 255) return 0x7f800000 | sign;
  return (exp << 23) | (uf & 0x807fffff);
}

求浮点数乘以2,转换为其实就是e + 1 = > exp + 1。所以除去临界条件,即如果exp == 0返回原数乘以2加上它的符号位。如果exp == 255则表示原数是NaN,返回其本身。 如果exp + 1 == 255则表示原数乘以2后溢出到正无穷,返回正无穷0x7f800000带上符号位即可。否则就返回结果



floatFloat2Int(f)

实现浮点数转为整数

代码

int floatFloat2Int(unsigned uf) {
  int exp = (uf & 0x7f800000) >> 23;
  int e_ = exp - 127;
  int sign = uf&(1 << 31);
  int frac = (uf & 0x007fffff) | 0x00800000;  //  M = 1. ...
  if (!(uf&0x7fffffff)) return 0;
  if (exp == 255) return 0x80000000u;
  if (e_ > 31) return 0x80000000u;
  if (e_ < 0) return 0;
  if (e_ > 23) frac = frac << (e_ - 23);
  else frac = frac >> (23 - e_);

  if (!((sign >> 31)^(frac >> 31))) return frac;
  else if (frac >> 31) return 0x80000000u;
  return ~frac + 1;
}

首先取出浮点数的各个部分(sign,expfrac),然后根据exp求出e,根据e的位数来移动frac或者判断临界情况。



floatPower2(x)

求2.0的x次幂

代码

unsigned floatPower2(int x) {
  int exp = 0x3f800000 >> 23;
  exp = exp + x;
  if (exp >= 255) return 0x7f800000;
  if (exp < 0) return 0;
  return exp << 23;
}

2.0(1.0 × 2^1)的位级表示:exp:1 + 127 = 128,frac = 0

所以2.0的x次幂,其实就是exp = x + 127

首先得到偏移之后的指数值exp,如果exp小于等于0(为0时,结果为0,因为2.0的浮点表示frac部分为0),对应的如果exp大于等于255则为无穷大或越界了。否则返回正常浮点值,frac为0,直接对应指数即可。



实验结果

在这里插入图片描述



实验总结

其实是第一次做国外课程的实验,csapp的实验又被称为是必做的实验,datalab实验对我的感觉就是让我更加熟悉计算机信息的底层表示,但位级操作却是真的难,总结以下几点不足。

  • 能独立做出来的题目很少,基本就简单的两三道,其它都是参考了网上的解答
  • 效率低,有时候一道题磨半天
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值