HNU-2024计算机系统实验-DataLab

写在前面:

这个实验目的在于补全所有函数,使其能够实现题意要求的功能,实验整体被分为两部分,一部分是整型,另一部分是浮点数,整型主要考察的是对位运算的相关处理和算法,浮点数部分主要考察的是对IEEE标准下浮点数表达方式的理解。强烈建议认真完成浮点数相关的函数补充(当然整型相关也要认真做),可以很好地加深对IEEE标准的理解,对将来的学习/考试有很大帮助。

一、实验项目一

1.1 项目名称

DataLab实验

1.2 实验目的

1.加强同学对位运算的理解和运用

2.加深同学对IEEE标准下浮点数表示方法的理解

1.3 实验资源

Datalab实验文件以及wsl2(搭载ubuntu20.04)

需要使用的实验文件有:bits.c、dlc以及btest(driver.pl相当于btest与dlc的组合,后面介绍),bits.c是主要的实验文件,需要补充的代码均在这个文件中,并且在文件开头会有一串英文提示(主要是告诉你函数整体的限制,例如不能使用的操作符、整型不能用条件分支等等,后续每个函数也中会有具体的限制),dlc是检测工具,用于检测你的每个函数文件是否符合对应的限制要求,如果执行完之后没有任何输出,表明所有函数文件均符合规则,btest文件则是功能检测文件,用于检测每个函数是否实现题给需求的功能,并给出每个函数的得分,完成本实验需要同时满足dlc不报错以及btest检测所有函数均满分。

1.4 整体限制条件:

1. 整型变量的范围限制在0~255,(即0~0xFF)

2. 不能使用全局变量

3. 整型部分的题目禁止使用任何控制结构,如 if、do、while、for、switch

4. 不能进行类型的强制转换

5. 不能调用任何其他函数

6.只能使用题目限定的操作符,并且只能使用有限次操作

1.5 准备工作:

首先在Linux的终端进入到datalab-handout目录,输入make all指令生成可执行文件btest、fshow和ishow(ishow和fshow,可以查看一个数在int类型和float类型下有无符号形式的值,可以不使用),也可以使用指令make btest只生成btest文件,许多同学在输入完make all指令或者使用./dlc bits.c之后,显示报错: No such file or directory,原因是没有安装交叉编译环境,输入指令进行安装:

sudo apt-get install gcc-multilib

安装完成后就可以正常执行make指令生成btest文件和使用dlc文件了,至此,准备工作已就绪。

之后每次更改bits.c中的文件后,需要输入make clean清除旧的btest文件,再重新进行make操作

二、实验任务

实验任务A:bitAnd

1.传入参数:int x,int y

2.可使用的操作符:~ |

3.最大操作符数量:8

4.分数:1

代码实现:

 * bitAnd - x&y using only ~ and | 
 *   Example: bitAnd(6, 5) = 4
 *   Legal ops: ~ |
 *   Max ops: 8
 *   Rating: 1
 */
int bitAnd(int x, int y) {
  return ~(~x | ~y);
}

本题利用德摩根律:x&y = ~(~x | ~y) 可以很容易得出答案

实验任务B:getByte

1.传入参数:int ,int n

2.可使用的操作符:! ~ & ^ | + << >>

3。最大操作符数量:6

分数:2

代码实现:

/* 
 * getByte - Extract byte n from word x
 *   Bytes numbered from 0 (LSB) to 3 (MSB)
 *   Examples: getByte(0x12345678,1) = 0x56
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 6
 *   Rating: 2
 */
int getByte(int x, int n) {
  return (x>>(n<<3) & 0xFF);

}

本题思路在于将需要获取的字节移动到最右侧,再与0xFF进行与操作,根据编号规则可知,将编号为n的字节移动到最右侧需要右移n个字节,即8n位,用左移3位得到8n。

实验任务C:logicalShift

1.传入参数:int x,int n

2.可使用的操作符:! ~ & ^ | + << >>

3.最大操作符数量:20

4.分数:3

代码实现:

/* 
 * logicalShift - shift x to the right by n, using a logical shift
 *   Can assume that 0 <= n <= 31
 *   Examples: logicalShift(0x87654321,4) = 0x08765432
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 20
 *   Rating: 3 
 */
int logicalShift(int x, int n) {
  return (x>>n) & ~(((1<<31)>>n)<<1);
}

由于C语言中右移操作>>是算数右移,对于负数会在左侧自动补1,所以需要将补1的位均置为0,本题需要利用算术逻辑的规则,先得到前n位为1,后32-n位为0的数,再按位取反,就可以得到前n位为0的数了,用于右移之后x前n位的置零。

实验任务D:bitCount

1.传入参数:int x

2.可使用的操作符:! ~ & ^ | + << >>

3.最大操作符数量:40

4.分数:4

代码实现:

方法一:

int bitCount(int x) {
  int temp = (((((((0x1 << 8)) | 0x1) << 8) | 0x1) << 8) | 0x1);
                                        //生成00000001 000000001 00000001 00000001的序列,以便后面的相加
  int ans = 0x0;
  ans = temp & x;                       //先计算每8个字节的第一个,将每一段的结果都加到ans里去
  ans = ans + (temp & (x >> 1));        //计算2/8
  ans = ans + (temp & (x >> 2));        //3/8
  ans = ans + (temp & (x >> 3));        //4/8
  ans = ans + (temp & (x >> 4));        //5/8
  ans = ans + (temp & (x >> 5));        //6/8
  ans = ans + (temp & (x >> 6));        //7/8
  ans = ans + (temp & (x >> 7));        //8/8
  ans = ans + (ans >> 16);              //先将第1,3和2,4分别相加
  ans = ans + (ans >> 8);               //再将上一步得到的结果加到最后8位中
  return ans & 0xff;                    //只取最后8位
}

方法二:

/*
 * bitCount - returns count of number of 1's in word
 *   Examples: bitCount(5) = 2, bitCount(7) = 3
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 40
 *   Rating: 4
 */
int bitCount(int x) {
	int a1=0x55;                             //01010101
    int a2=0x33;                             //00110011
    int a3=0x0F;                             //00001111
    int a4=0xFF;                             //00000000 11111111
	int a5=a4 | (a4<<8); 
	a1=a1 | (a1<<8);
	a1=a1 | (a1<<16);
    a2=a2 | (a2<<8);
    a2=a2 | (a2<<16);
    a3=a3 | (a3<<8);
    a3=a3 | (a3<<16);
    a4=a4 | (a4<<16);                         //生成相应的掩码
	x=(x & a1)+((x>>1) & a1);
	x=(x & a2)+((x>>2) & a2);
	x=(x & a3)+((x>>4) & a3);
	x=(x & a4)+((x>>8) & a4);
	x=(x & a5)+((x>>16) & a5);
	return x;                                //设置掩码将不参与计算的位置零。
}

由于方法一打了注释,这里重点介绍方法二:

首先,对于一个二进制数中1的个数,等价于把这个二进制数的每一位加起来的结果,为了提高效率本题采用二分法,分组进行求和,从右至左编号为1-32,首先一个数一组,将偶数组的数加到奇数组,再两个数一组、四个数一组、……、直到十六个数一组,重复第一次求和的操作,得到的结果即为该二进制数中1的个数。(为了实现分组求和,需要引入掩码来对原二进制数进行处理,即图中的a1~a4)

实验任务E:bang

1.传入参数:int x

2.可使用的操作符:~ & ^ | + << >>

3.最大操作符数量:12

4.分数:4

代码实现:

/* 
 * bang - Compute !x without using !
 *   Examples: bang(3) = 0, bang(0) = 1
 *   Legal ops: ~ & ^ | + << >>
 *   Max ops: 12
 *   Rating: 4 
 */
int bang(int x) {
	int x1=(~x+1);
  return ((x | x1)>>31)+1;//利用符号位来分析判断,注意不能使用异或
}

对于这道题目,要实现取反操作:输入0返回值为1,输入其他值均输0,这个时候就要考虑到0和其他所有数字的一个共同区别,即0的相反数是本身,符号位不发生变化,所以我们可以利用这一点,将x与x的相反数进行异或,然后把符号位算数右移至最右侧,0对应的是全0,而其他数是全1,再加上1就完成了取反操作。

实验任务F:tmin

传入参数:void

可使用的操作符:! ~ & ^ | + << >>

最大操作符数量:4

分数:1

代码实现:

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

本题较为容易,需要知道最小的int型数字为0x80000000,将其输出即可,需要注意的是本题限定使用的常数范围在0xFF之内,所以用左移操作来得到结果。

实验任务G:fitsBits

传入参数:int x,int n

可使用的操作符:! ~ & ^ | + << >>

最大操作符数量:15

分数:2

代码实现:

/* 
 * fitsBits - return 1 if x can be represented as an 
 *  n-bit, two's complement integer.
 *   1 <= n <= 32
 *   Examples: fitsBits(5,3) = 0, fitsBits(-4,3) = 1
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 15
 *   Rating: 2
*/
int fitsBits(int x, int n) {
	int bias=33+(~n);
	return !(x^((x<<bias)>>bias));

}

本题考虑对于正数体现为前33-n位为0,负数体现为前33-n位均为1,也就是说前32-n位是没有实际作用的填充位,那么左移32-n位,再右移32-n位得到的数应该和原数相等,就可以得到答案,相等用异或取反判断。

注:在完成本题时,会出现代码功能正常,但是btest跑出来得分为0的情况,这里需要从btest的工作原理来解释:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值