Lab1:Data Lab

Lab1:Data Lab

CSAPP Lab1:Data Lab (虚拟机安装+Lab环境配置+函数实现)-CSDN博客我当翻译看emmm

一、相关命令

开始前:

unix> ./dlc bits.c		// 检查bits.c否符合dlc
unix> ./dlc -e bits.c 	// 打印每个函数用了多少个运算符

编译:

unix> make clean	// 删除btest相关文件,用于测试
unix> make btest	// 生成btest相关文件,用于测试

评测:

 ./btest		// 测试所有函数的正确性并输出错误信息
 ./btest -g		// 以简洁的形式测试所有函数,不发送错误消息
 ./btest -f foo	// 测试函数foo的正确性
 
 ./btest -f foo -1 27 -2 0xf  // 用特定参数测试函数foo的正确性:

二、编写时

1.假设前提

1.补码表示32位整数表示,
2.算数右移
3.当移位量小于0或大于31,移位具有不可预测的行为

对于需要您实现浮点运算的问题,编码规则较不严格。您可以使用循环和条件控制。您可以同时使用int和unsigned。您可以使用任意整数和无符号常数。您可以对int或unsigned数据使用任何算术、逻辑或比较操作。

2.禁止

1定义或使用任何宏。
3在此文件中定义任何其他函数。
4调用任何函数。
5使用任何形式的强制转换。
6使用除int或unsigned之外的任何数据类型。这意味着您不能使用数组、结构或联合。
7使用任何浮点数据类型、操作或常量。

三、函数实现

int bitXor(int x, int y) {
  return ~(x&y)&~(~x&~y);
}
PS:答案是猜出来的,就感觉应该是这样,感觉是从我之前看书看了类似的东西来的
int tmin(void) {

  return 1<<31;

}
int isTmax(int x) {
  return (!((x+1)^~x))&(!!(~x));
}
PS:最开始想的是x^01111...1的,然后凑出来Tmax的,但发现凑不出来,而且好多符号没用。
然后想了下这是个判断题,可以先假设x是Tmax,然后看下有什么性质。很结合给的符号启发容易找到如果是Tmax,x+1=~x,但是由于没有等号,可以^和!表示。!((x+1)^~x
然后-1特殊情况美国,想了下,-1+1就变成0了,而Tmax是非0。然后一个坑点是&,这是位运算而不是逻辑运算,当时直接写了&x。实际可以0和1看成000...0/1。&只管最后一位,就用!。所以&(!!(~x))。
int allOddBits(int x) {
  int a = 0xAA << 8;
  int b = a|0xAA;
  int c = b << 16 | b;
  
  return !(c^(x&c));
}
PS:最开始直接写的0XAAAAAAAA,但看别人都这么写,我问gpt,gpt说更直观展示掩码的过程,先姑且这么认为吧
int negate(int x) {
  return ~x+1;
}
//PS:虽然是背的,但想起那个数轴图
int isAsciiDigit(int x) {
  
  return (!((x>>3)^(0x6))) | (!(x^0x38)) | (!(x^0x39));
}
ps:我是傻子,我还在想怎么模拟比较符号。0x30 ~ 0x37 的位级表示为 0011 0xxx,所以只要检查除了后三位的前面的,0x38和0x39单独检验
int conditional(int x, int y, int z) {
  x = ((!!x) << 31)>>31;
  return (x&y)|(~x&z);
}
int isLessOrEqual(int x, int y) {
  int a = !(x^y);

  int sign_x = (x >> 31);
  int sign_y = (y >> 31);
  int b = ((sign_x^sign_y)&(!sign_y));

  int c = !(((x + (~y+1))>>31)^0xFFFFFFFF);
  int d = !(sign_x^sign_y);

  return a | b | (d&c);
}
PS:x、y同号不可能溢出,异号可能溢出。a是相等情况;b是异号,只有y为正,x为负才有可能成立;c是同号情况。
int logicalNeg(int x) {
  
  return ((x | (~x+1))>>31)+1;
}
pS:想不到啊,原来用相反数来玩,看相反数符号位
int howManyBits(int x) {
  x = (~(x>>31)&x)|((x>>31)&~x);

  int b16,b8,b4,b2,b1,b0;
  b16 = (!!(x>>16)) << 4;
  x = x >> b16;

  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;
}

伪代码:
x = x是负数吗?-x:x
i = 31, j=0
while(i<j)
{
	mid = (i+j)/2;
	如果第[i,mid]含1
		j = mid
	否则
		i = mid-1
}

return mid+1
但发现i和j还有mid不好实现,换个思路,上面二分是用下标,如果我直接移动原来的x呢,就我指定mid,比如mid为16
if 高16位有1
	b16 = 16;	// 标志,表明低位有16(1 0000)个
	x = x >> 16;
否则
	b16 = 0;	// 标志,还是得从第一个低位-16查找
然后b8、b4、b2、b0
unsigned floatScale2(unsigned uf) {
  unsigned sign = (uf >> 31) & 0x1;
  unsigned eps = (uf >> 23) & 0xFF;
  unsigned frac = uf & 0x7FFFFF;

  if(!(eps^0xFF))  // eps==0xFF
  {
      return  uf;
  }else if(!eps)  // eps==0
  {
      frac = frac << 1;
  }else
  {
      eps = eps + 1;
  }
  
  return (sign << 31) | (eps << 23) | frac;
}
int floatFloat2Int(unsigned uf) {
  unsigned sign = (uf >> 31) & 0x1;
  unsigned eps = (uf >> 23) & 0xFF;
  unsigned frac = uf & 0x7FFFFF; 
  
  int E = eps - 127;
  if(E<0) 
  {
      return 0;
  }else if(E>=31) 
  {
    return 0x80000000u;
  }else
  {
      frac =  frac | (1<<23);
      if(E>=23)
      {
        frac <<= (E-23);
      }else
      {
        frac >>= (23-E);
      }
  }

  if(sign)
    return -frac;
  else  
    return frac;
}
unsigned floatPower2(int x) {
    if(x>127) // too large
    {
      return 0xFF << 23;
    }else if(x<-148)  // too little,e/x = 1 - 127 - 22 (frac = 000...001)
    {
      return 0;
    }else if(x<-126)  // 00000000 11111...111
    {
        return  1 << (x+127-1+22);
    }else
    {
        return (x+127) << 23;
    }
}

四、小结

突然发现几个版本的lab不一样,目前我只知道datalab2016、2019、2022这三个版本不一样。我写的2022然后做不出来找题解发现几乎是2019版本的。死磕了两个小时还没有题解,我直接手动放弃,还是去做2019版的。然后中途一直有warning,emmm,我不管,只要没error就行。

做完了收获就是认识到好多运算实际上可以用位级运算实现,至于怎么在物理上实现位级运算,有点好奇,但emmm时间有限,不能去探究。

有些题脑壳都想破了的想不到,头秃.jpg。但循循渐进,最开始!!和mask掩码我是没有概念的,看提示和目标,实在是做不出来了看题解。原来使用这种方式解决的吗.jpg

  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 好的,这里是您要求的回答: 这个问题涉及到计算机系统的实验课程——深入理解计算机系统(CS:APP)的第一个lab任务,也称为Data Lab。这个任务要求学生使用C语言编写函数来实现不同的位级操作,从而深入理解计算机中数字的存储和运算。 ### 回答2: 在Data Lab的第二部分中,我们学习了如何用不超过十六个操作来实现不同的位运算。这些操作包括移位,逻辑运算,比较和掩码等。通过这些操作的实现,我们可以进一步理解底层计算机系统中位运算的实现原理。 在实现这些操作时,我们需要了解底层计算机系统的运算和数据类型。如符号扩展、零扩展和反码等。同时,在编写代码时需要熟练使用位运算的操作符号以及一些基本控制流语句如循环、条件语句等。 除了实现这些基本操作,我们也需要应用这些操作来解决一些实际问题。例如,实现一个函数,将一个十六进制数按位翻转,或是计算一个整数二进制表示中1的数量等。 通过Data Lab的学习,我们深入了解了计算机系统中底层的位运算实现原理,并学会了如何用简洁高效的代码实现这些操作。同时,这些操作也常常被用在各种领域的计算机编程中,对于未来的学习与工作都有很大的帮助。 ### 回答3: 在《深入理解计算机系统》lab1:data lab(二)中,我们主要学习了位运算和两个的补码表示。这些知识对于我们了解计算机的原理和编码方式非常重要。 在这个实验中,我们需要完成一些与位运算相关的任务。其中包括: 1. 实现位运算。我们需要用 C 语言实现一些常见的位运算,如与、或、非、异或、左移、右移等。 2. 计算 x 的相反数。 3. 检查 x 是否为零。 4. 判断 x 的符号是否为负数。 5. 计算 x 和 y 的和,但不能使用加法运算。 为了完成这些任务,我们需要对 C 语言数据类型的细节和位运算的机器级实现有一定的了解。例如,我们要了解有符号整数和无符号整数的区别,以及它们在机器上的表示方式。我们还需要理解位运算的计算过程,包括位移的规则、符号扩展和逻辑运算等。 通过这个实验,我们可以更深入地理解计算机的工作原理,学会用底层的方式实现高级的运算,掌握常用的位运算技巧。这对于提高编程的效率和代码的可读性都有很大帮助。同时,这也为后续的计算机科学学习打下了坚实的基础。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值