计算机系统实验——datalab(完整代码链接)

计算机系统实验——datalab

完整代码:

链接:https://pan.baidu.com/s/1W74CDNnetD8YNbbqXAlSqw 
提取码:dzwe 

目录

实验题目:

实验目的:

实验环境:

实验内容及操作步骤:

一、实验准备,

二、开始实验

第一步,阅读datalab中的相关资料(README、bits.c),明确实验要求;

第二步,一个个的bits.c中补充缺失的函数并测试

实验结果及分析:

收获与体会:


实验题目:

LAB2-datalab

实验目的:

通过此次实验,进一步熟悉整型及浮点数的位表达形式,实现常用二进制运算的常用方法。

实验环境:

个人电脑、linux发行版本

实验内容及操作步骤:

一、实验准备,

在所使用的电脑平台上安装VMWare tools(开启文件夹共享,以便接下来的实验)

  1. 将VMWare tools中的gz文件移动到桌面并解压
  2. 在终端中输入指令

cd desktop

cd vmware-tools-distrib

 cd sudo ./vmware-install.pl

安装过程不断回车,直至安装完成

 

  1.      3. 开启共享文件夹

【虚拟机设置】-【选项】-【共享文件夹】中添加共享文件夹,将LAB-datalab所在文件夹共享到虚拟机。

 

二、开始实验

第一步,阅读datalab中的相关资料(README、bits.c),明确实验要求;

我们需要补充bit.c中的函数,所有的工作都只需修改 bits.c 文件,然后通过btest, dlc和 BDD checker来测试代码。

 

任务指引主要有以下一些说明:

1、整型的范围是 0 到 255(0xFF),不允许用更大

2、只能包含参数和局部变量

3、一元操作符 ! ~

4、二元操作符 & | + << >>

5、不允许的操作有:

使用任何条件控制语句、定义和使用宏、定义其他的函数、调用函数、使用其他的操作符、使用类型转换、使用除 int 之外的类型(针对整型)、使用除 int, unsigned 之外的类型(针对浮点数)

可以认为机器:

      1、使用 2’s complent,32位

   2、执行算术右移

   3、移动超过字长的位数会出问题

 

 其他需要注意的事情有:

1、使用 dlc(data lab checker) 来检测代码的合法性(有没有使用不给使用的符号语法等等)

2、每个函数都有操作数的上限值,注意 = 不算

3、使用 btest 来测试结果的正确与否

4、使用 BDD checker 来正规测试你的函数

 


第二步,一个个的bits.c中补充缺失的函数并测试

 

  • 1. 用或与非实现与

根据德摩根律,,可以得到最简单的表达式:

 

  • 2. 取整型的第多少个字节

编号是从LSB(Least Significant Bit,最低有效位为0)到MSB(Most Significant Bit,最高有效位为3)。

利用按位与&,1&X=X,0&X=0的特性,只要把要取的第n个字节移到最低位后和0xff按位与,第n个字节会保留,编号大于n的字节会被清零。因为1个字节是8位,因此取第n个字节时要先将其右移8*n位,8*n用位运算可表示为(n<<3);

 

  •     3. 逻辑右移

因为c语言里的>>运算符默认是算术右移(算术右移符号位补位,逻辑右移0补位),所以可以先进行算术右移,再将补位的符号位(可能是0或1)换成0;

假设要逻辑右移n位,就需要将最高位的n位符号位全部替换成0,那么就可以利用左边n位为0,右边32-n位为1的二进制码与算术右移n位后的原码按位与&,便可得到逻辑右移n位后的目标数。

构造这个二进制码可以用:1 << 31得到100...,算术右移n位,得到1...10...0,共n+1位为1。再左移1位,即可得到 1...10...0,共n位为1,再将这个数取反即可。(当然也有其他构造方法)

实现:

 

 

  •     4. 求一个数的二进制表示中1的位数;

 

采用二分法,自底向上,先计算x每两位中1的个数,由count对应两位存储。以此类推,计算每4位、8位、16位中1的个数,最后的整合结果即为x中的1的个数。每次“错位”相当于一次相加。

 

原理分析:

以1101 0010为例

实现:

 

  •    5. 不利用逻辑符号!求一个数的逻辑非

也就是判断该数的二进制位是否全为0,若全为0则返回1,否则返回0

只有当x=0时,~x为全1,~x+1为全0(逸出),x|(~x+1)的最高位为0。

只要x不为0,x与 ~x+1的最高位一定有一个为1,因此,~(x|(~x+1))即为结果。只需要将x|(~x+1)右移31位,与1按位与,再按位取非即可。

实现:

 

  •     6. 返回最小的二进制补码integer

即为最高位为1,其余各位为0。最高位为符号位,负数,再减小一位即为正数,因此是最小的整数。

实现:

 

  •     7. 判断x能否由n位二进制补码表示

将x先左移shift,再右移shift,其实是保留了低n位,其余各位置0。shift的值实际上是32-n,利用了补码原理。

 将x与该值按位异或,只有当x的第31位~第n位全为0时,按位异或的结果才为0;否则便为1。因此,只需要将按位异或的结果取非,即可得知x是否超过了n位二进制所能表示的范围。

-4、5的原理:

 

实现:不允许使用减,因此用~x+1表示负数

 

  •     8. 计算 x / (2^n)

如果x为整数,直接x>>n即为正确结果,但由于代码不能使用if语句,因此需要考虑其他方法。

对于负数,除法是向0取整,而右移位是向负取整,因此需要加上偏置量2^n-1(低n-1位全为1,其余各位全为0)。通过x>>31得到符号(全1或全0),与2^n-1按位与即可得到偏置量。x加上偏置量,向右移n位。(正数则不加偏置量)

 

注意:右移实现除法中的偏置量问题:

在计算机中,如果两个int型数ab作除法(a/b),当a不能被b整除的时候,表达式的结果为(a/b)的商。这个商是通过向下取整得来的。即对于17/16,结果在区间(1,2)上,向下取整,得到1。考虑a<0的情况,当a=-17时,结果在(-2,-1)上,向下取整,得到-2。而我们期望的结果是-1。通过与偏置量相加,将结果偏移到(-1,0)上,再向下取整,就得到-1

当不能整除时,计算机都会采取向下取整运算。对于正数,向下取整是符合我们习惯的,对于负数,我们的期望时绝对值向下取整,即整体向上取整,这与计算机的向下取整不符合,所以就要通过偏置量来实现。

关于偏置量的取值,当a>=0时,偏置量值为0;当a<0时,设偏移量为n,偏置量取值为(2^n-1)

 

实现:

用~0表示-1;

 

  •     9. 求相反数

 

按位取反加一即可

实现:

 

  •     10. 判断是否为正数

正数符号位为0,负数符号位为1,向右移31位得到全0(正)或全1(负),再与1相与后得到0(正数)、1(负数),再取反得到正确结果;

 

实现:

 

测试结果:

用了3个操作符;

btest测试错误,因为测试0的时候应该返回0,但是我的程序返回了1;

原因:0的符号位也是0,忽略了x>0返回1的条件,使0也返回了1;

 

修改程序:

当x为正数时,x>>31为全0,!((x>>31)|(!x))即为!!x,x不为0时结果为1。

x为负数时,x>>31为全1,(x>>31)|(!x)为全1,!((x>>31)|(!x))结果为0。

 

测试结果:

用了4个操作符

结果正确;

 

  •     11. 判断小于等于

需要判断x-y的符号位,但是如果x正、y负或x负y正则可能越界,因此不能直接判断,分为几种情况:

  1. x负、y正,此时x符号位1,y符号位0,将x、y右移31位后与1相与,得到的结果为x变为1,y变为0,因此此时将x与!y相与得到1,也只有x=1、y=0,该式才为1;
  2. x、y同符号,则判断x-y的符号,将x-y右移31位后与1相与,x-y是正数则得到0,取反得1;
  3. x、y相同,x^y取反得到1;

因此将上面的三个式子相或后得到正解;

实现:

测试结果:

18个操作符,满足条件;

中间出现过许多次错误,主要原因是情况的划分不正确,以及0、1与、或之间有些混乱,参考了网上代码后终于修正;

 

  •     12. log2(x),即判断多少位二进制表示

 

我们要找的就是最高位的那个1,并且返回它的位置;

可以使用二分法,先在左16位找:

    如果有1则在左边16位的前8位中找,如果没1则在右边16位中的前8位找(丢弃左16位),一直划分下去直到仅剩1位,那一位就是我们要找的最高位1;

    注:x>0,算数右移补0;

    用shift表示丢掉的位数,如果丢掉高位则shift为0,如果丢掉低位则是丢掉的位数(为了求最高位1的位置);

 

实现:

 

测试:

 27个操作符,满足条件;

测试正确;

 

  •     13. 返回和-f相等的二进制(返回引用都是unsigned)

与第二章作业中的2_92相似;

参数和返回结果都是无符号整数,但是可以解释成单精度浮点数的二进制表示。

根据IEEE 754标准:阶码全1,尾数非全0的表示无效数NaN。

判断f是否为NaN,是则直接返回,否则将符号位取反;

 

实现:

完全用2_92的代码:

 

测试结果:

7个操作符

 

  •     14. int型转换为float

符号位(sign):

    看最高有效位即可;

尾数:

    int型(二进制表示)可假设小数点在最低有效位右边,循环左移n-1次,使得第一个有效数字1在最高有效位,小数点在其右边,可以计算小数点移动了32-n位),那么小数点右        边第1位(首位)到第23位就是浮点数表示的尾数部分了,因为这里只要取23位所以存在精度问题,这里采取四舍五入向偶数舍入的方式;

阶码部分:

    看小数点移动的位数,加上偏置量(float中为127)即可。即(127+32-n)<<23。

    0x01ff为111111111,0x0100为100000000, 判断是否需要进位,如果需要,flag为1

 

实现:

 

 

测试结果:

 17个操作符,满足条件

结果正确;

 

  •     15. 返回以unsinged表示的浮点数二进制的二倍的二进制unsigned

分为几种请况:

1、 非规格化的数

(f&0x007FFFFF)<<1,为当阶码全0时,令尾数左移1位

(0x80000000&f)将符号位恢复;

2、规格化数。

f=f+0x00800000即:若是规格化数,对它的阶码加1

3、如果都不满足的话最后会返回uf原来的值

 

实现:

测试:

 9个操作符

   

 

实验结果及分析:

1dlc测试:

    

所有操作符的数量都符合限制;

2btest测试:

所有函数功能正确;

从上述dlc与btest测试中可以看出,15个函数均满足操作符号数限制以及功能测试,成功编写并通过了bits.c中的15个函数空缺部分;

 

收获与体会:

通过本次实验,我更进一步的掌握了浮点数、整数的二进制表示,初步理解并学会了位级操作,学会了利用普通的位级操作符来实现一些简单的和一些较复杂的操作,如取反、int转换为float等,在填充这些函数时,我受益匪浅。

在设计这些函数的过程中,将位级操作与算法设计融合起来,在二进制层面上设计算法更进一步加深了我对位级操作的理解和掌握,提供了设计算法、实现问题的新的基于位级操作的思想。

在实验过程中出现过很多次错误,包括函数的设计思想的错误,在网上查询资料后最终解决,这个过程中也学到了很多。

  • 12
    点赞
  • 62
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值