纯小白的csapp datalab

纯小白的csapp datalab

前言

​ 因为自己的水平还不够,所以data lab写了蛮久的,这里记录一下下,就当是一个笔记了,题目全部做出来了,都是自己写的,可能有不够完善的地方,有些题目应该还有更简便的答案,大佬可以教导我一下,除了最后一题,有时候超时有时候不超时(答案是对的),其它题目都是满分。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yLqZfDuh-1619921437551)(D:\Typora\笔记\CSAPP\assets\image-20210221164336058.png)]

准备工作

​ 因为需要搭建Linux环境(需要用Linux写这个lab),平时用的都是windows,所以需要下载VMware安装Linux虚拟机,这里我就简单跳过,我安装的是Ubuntu,详细的步骤可以参照大佬的教程

​ 我在配置好之后遇到了一些些小问题,比如没有安装一些基础的工具包,导致gcc无法使用,可以自行百度。

如何使用

​ 首先到官网下载lab的文件到你的Linux中,之后在终端输入unix> tar xvf datalab-handout.tar.将文件解压,文件中有readme,可以看一下。

​ 其中大概内容就是:我们只需要改写bit.c这一个文件,在这个文件的开头有写lab的注意事项,我在下面会提到。其它文件都是一些工具,其中最常用的就是make、btest、和dlc。

​ 如何使用可参考这个pdf

注意事项

​ 接下来就是最重要的注意事项,其中分为int题和float题,注意事项不同,主要根据题目上方的提示进行做题。

int题

允许:

  1. 整数常量0到255 (0xFF)。不允许使用像0xffffffff这样的大常量。
  2. 函数参数和局部变量(没有全局变量)。
  3. 一元整型运算!~。
  4. 二进制整数运算& ^ | + << >>。

不允许:

  1. 使用任何控件结构,如if、do、while、for、switch等。
  2. 定义或使用任何宏。
  3. 在此文件中定义任何附加函数。
  4. 调用任何函数。
  5. 使用任何其他操作,如&&,||,-,或?
  6. 使用任何形式的铸造。
  7. 使用除int以外的任何数据类型。这意味着不能使用数组、结构或联合。

float题

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

  1. 义或使用任何宏。
  2. 在此文件中定义任何附加函数。
  3. 调用任何函数。
  4. 使用任何形式的铸造。
  5. 使用除int或unsigned以外的任何数据类型。这意味着不能使用数组、结构或联合。
  6. 使用任何浮点数据类型、操作或常量。

题目

int题

bitXor

题意:只能使用~和&来实现x^y的效果。

/* 
 * 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) & ~(~y & x));
}

解题思路:如果学过离散数学,这题很简单x^y = (~x & y) | (~y & x),然后使用德摩根定律。

tmin

题意:返回最小德二进制数的补码。

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

解题思路:略过。

isTmax

题意:如果x是最大值,则返回1,否则返回0。

/*
 * 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 y = x + 1;
  return !y ^ !(~y ^ x);
}

解题思路:这里一个关键的点就是 最大值+1 的逆就等于最大值,所以可以用^来起到一个判断的效果。但是要注意0xffffffff+1 的反也等于 0xffffffff,所以在前面要补上一个判断。

allOddBits

题意:如果x中所有奇数位都设置为1,并且从0(最低有效位)到31(最高有效位)进行编号,则返回1。

例如:allOddBits(0xFFFFFFFD) = 0, allOddBits(0xAAAAAAAA) = 1

/* 
 * 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 y = ((((((0xAA << 8) + 0xAA) << 8) + 0xAA) << 8) + 0xAA);
  return !((x & y) ^ y);
}

解题思路:这题的思路比较简单,不用管偶数位,直接让 x & 0xAAAAAAAA 这时会把偶数位都至0,再 ^ 0xAAAAAAAA,如果为0,则说明x的奇数位都为1。这里要注意的是我们不能直接使用0xAAAAAAAA,所以要通过位移来得到0xAAAAAAAA。

negate

题意:返回-x。

/* 
 * negate - return -x 
 *   Example: negate(1) = -1.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 5
 *   Rating: 2
 */
int negate(int x) {
  return ~x + 1;
}

解题思路:略过。

isAsciiDigit

题意:如果0x30 <= x <= 0x39(字符’0’到’9’的ASCII码)返回1。

例如:isAsciiDigit(0x35) = 1。isAsciiDigit(0x3a) = 0。isAsciiDigit(0x05) = 0.

/* 
 * 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 y = x + ~0x2f;
  int z = x & 0xf;
  int m = ~0xa + 1;
  return (!(y & ~0xf)) & ((z + m) >> 31);
}

解题思路:这道题,首先要判断x的范围是否在 0x30 ~ 0x3f 之间,其次得到x的后四位z,用 z - a 并判断其是否大于等于=,如果不是,则范围在 0x30~0x39 之间。

conditional

题意:x ? y : z

/* 
 * 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 t = ~(!!x) + 1;
  return (t & y) | (~t & z);
}

解题思路:使用 !!x 可以用来判断x是0还是非零,如果为0,取反加一还是为0,如果非零,取反加一为0xffffffff,再利用 0xffffffff & x = x,0 & y = 0 的性质即可得出结果。

isLessOrEqual

题意:如果x <= y则返回1,否则返回0。

/* 
 * 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 m, n, z;
  m = x>>31 ^ y>>31;//当x和y异号时m=1
  n = !((x ^ ~y) + 1) | (((x + (~y + 1)) >> 31) & 1);//两者相等或x - y < 0
  z = (x>>31) & 1;
  return (m & z) | (~m & n);
}

解题思路:这道题使用了上一题中x ? y : z的格式,首先判断x和y是否异号,如果异号,则看x的符号位,如果x小于0,则返回一,如果x大于0,则返回0。如果x和y同号,则需要判断两者相等或x - y < 0即可。

logicalNeg

题意:不使用 ! 但是达到 ! 的效果。0返回0,非零返回1。

/* 
 * 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) {
  int n;
  n = ((~x + 1) ^ x) >> 31;
  return (~n & ~(x >> 31)) & 1;
}

解题思路:这道题,我们只需要抓住一个特点,就是 -0 == 0,但是还有 -Tmin == Tmin,所以再判断x的符号位即可。

howManyBits

题意:返回在二进制补码中表示x所需的最小位数。

例如:

  • howManyBits(12) = 5
  •        howManyBits(298) = 10
    
  •        howManyBits(-5) = 4
    
  •        howManyBits(0)  = 1
    
  •        howManyBits(-1) = 1
    
  •        howManyBits(0x80000000) = 32
    
/* 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 sign=x>>31;
  x = (sign & ~x) | (~sign & x);//如果x为正则不变,否则按位取反

  // 不断缩小范围
  b16 = !!(x >> 16) << 4;//高十六位是否有1
  x = x >> b16;//如果有(则需要16位),则将原数右移16位
  b8 = !!(x >> 8) << 3;//剩余位高8位是否有1
  x = x >> b8;//如果有(则需要16+8=24位),则右移8位
  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;//+1为加上符号位
}

解题思路:

​ 这道题首先要理解题意,返回在二进制补码中表示x所需的最小位数,举个例子2 = 0100,需要四位,-6 = 1010,四位,但是我们注意到,负数和正数不一样,正数需要找到第一个1,而负数是找到第一个0,所以我们要先对x进行判断,如果x为正则不变,否则按位取反,统一找到第一个1,再加上1(符号位)。

​ 所以我们使用二分法的方式,首先判断高16位是否有1,如果有,则不用管剩下的16位(所以需要向右移16位),且令b16 = 16,如果没有,则需要看低16位是否有1。接着观察改变过后的x的高8位,同理,找到最后,将b全部加起来,还需要加上1(符号位)即可。

float题

略(源文件突然没了,得重写了)

总结

我的方法不一定是最好的方法,有不足之处请大佬指出。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值