计算机系统实验 :APP DATA Lab2

本文详述了一次计算机系统实验,重点介绍了如何实现15个不同的二进制操作,如位与、取字节、逻辑右移等。通过实验,作者体会到知识的相通性和解决复杂问题的策略,所有函数均通过了测试,符合编码指导原则。
摘要由CSDN通过智能技术生成

实验题目: APP Data Lab

Directions to Students :

实验目的:

Your goal is to modify your copy of bits.c so that it passes all the tests in btest without violating any of the coding guidelines.

我的目标是修改bits.c文档,完成所有函数的编写,利用dlc和btest两个工具通过所有的测试

实验环境:ubuntu12.04环境

实验内容及操作步骤:

根据要求编写函数:

(1) bitAnd

函数功能:两个数的与操作

实现要求:

bitAnd - x&y using only ~ and |

Example: bitAnd(6, 5) = 4

Legal ops: ~ |

Max ops: 8

Rating: 1

实现思路:利用摩根定理,将x and y=(x or ~y)

实现代码:

int bitAnd(int x, int y) {

return ~((~x)|(~y));

}

(2) getByte

函数功能:取出一个int数据指定的字节
实现要求

  • 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

实现思路:
首先我们将n左移3位,扩展到8的倍数,然后右移n<<3,去除字节
实现代码:

int getByte(int x, int n) {

x=x>>(n<<3);

return x&0xff;

}

(3) logicalShift

函数功能:逻辑右移

实现要求:

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

实现思路:

LogicShift实现并不复杂,但是必须注意的是,是逻辑右移不死算数右移,也就是说,如果直接进行移动会导致符号位的填充现象。因此我们要消除因为符号位填充导致的错误,这里用temp=0x7fffffff,右移n-1位,然后与x>>n相与消除填充符号位

实现代码:

int logicalShift(int x, int n) {//注意是逻辑右移,不是算数右移,不能自动补符号位

int temp;

x=x>>n;

temp=~(1<<31);//0x7fffffff

temp=((temp>>n)<<1)+1;//右移n-1位,制造0000,用于消除符号位

return x&temp;//消除最高符号位

}

(4) bitCount

函数功能:计算一个二进制数中1的个数

实现要求:

bitCount - returns count of number of 1’s in word

Examples: bitCount(5) = 2, bitCount(7) = 3

Legal ops: ! ~ & ^ | + << >>

Max ops: 40

Rating: 4

实现思路:

这里的做法我一开始没有想到,但是从网上了解到了一种思路,也就是二分法,我们首先用01相间的一组数据去与x做这样的操作x=(x&list2)+((x>>1)&list2),可以算出2位中1的个数,同样的我们用0011相间的一组数去与x做:x=(x&list4)+((x>>1)&list4)可以计算4位中的1,然后用00001111做同样的操作,得到8位中的1,最有右移x,计算每8位的结果。

实现代码:

int bitCount(int x) {

int list2=(((((0x55<<8)+0x55)<<8)+0x55)<<8)+0x55;//构造0101 0101 0101 0101 0101 0101 0101 0101

int list4=(((((0x33<<8)+0x33)<<8)+0x33)<<8)+0x33;//构造0011 0011 0011 0011 0011 0011 0011 0011

int list8=(((((0x0f<<8)+0x0f)<<8)+0x0f)<<8)+0x0f;//构造0000 1111 0000 1111 0000 1111 0000 1111

x=(x&list2)+((x>>1)&list2);//计算2位中的1

x=(x&list4)+((x>>2)&list4);//计算4位中的1

x=(x&list8)+((x>>4)&list8);//计算8位中的1

//现在我们搞定每个字节中的值(8位中的1),接下来我们合并4个字节中的1

x+=(x>>8);

x+=(x>>16);

return x&0x3f;

}

(5) bang

函数功能:逻辑非操作

实现要求:

bang - Compute !x without using !

Examples: bang(3) = 0, bang(0) = 1

Legal ops: ~ & ^ | + << >>

Max ops: 12

Rating: 4

实现思路:

这个函数实现较为简单,直接利用符号扩充的特点将x取补码,然后与x相或,右移31位+1,如果是一个非0数,得到的结果是-1+1=0,否则为1.

实现代码:

int bang(int x) {

return (((~x+1)|x)>>31)+1;//利用符号扩充的特点

}

(6) tmin

函数功能:返回二进制最小整形数据

实现要求:

tmin - return minimum two’s complement integer

一的补码(one’s complement) 指的是正数=原码,负数=反码

二的补码(two’s complement) 指的就是通常所指的补码

Legal ops: ! ~ & ^ | + << >>

Max ops: 4

Rating: 1

实现思路:

将1右移31位,送至最高位即可

实现代码:

int tmin(void) {//二进制的最小补整数10000000000000000000000000000000

return 1<<31;

}

(7) fitsBits

函数功能:判断一个整型能否被n位二进制补码表示

实现要求:

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

实现思路:

能否用n位表示,我们可以将x左移32-n然后右移32-n位,将x的符号全部填充为第n位的二进制数,如果说这个结果和x相等,那么说明可以表示,否则不能表示。

实现代码:

int fitsBits(int x, int n) {

int y;

n=(~n)+1;

y=(x<<(32+n))>>(32+n);//得到符号扩展的x

return !(x^y);

}

(8) divpwr2

函数功能:计算x/(2^n)的值并且向0取整

实现要求:

divpwr2 - Compute x/(2^n), for 0 <= n <= 30

Round toward zero

Examples: divpwr2(15,1) = 7, divpwr2(-33,4) = -2

Legal ops: ! ~ & ^ | + << >>

Max ops: 15

Rating: 2

实现思路:

这里实质上以做右移n位的操作,但是需要区分是正数还是负数,如果是正或0直接右移n位,为负数则需要加上偏置量后再进行移位操作。其中偏置为2^n-1.

实现代码:

int divpwr2(int x, int n) {

int temp=((1<<n)+(~0))&(x>>31);

return (x+temp)>>n;

}

(9) negate

函数功能:计算负数

实现要求:

negate - return -x

Example: negate(1) = -1.

Legal ops: ! ~ & ^ | + << >>

Max ops: 5

Rating: 2

实现思路:补码操作,取反加1

实现代码:

int negate(int x) {

return (~x)+1;

}

(10) isPositive

函数功能:判断一个数是否是正数返回1,否则返回0

实现要求:

isPositive - return 1 if x > 0, return 0 otherwise

Example: isPositive(-1) = 0.

Legal ops: ! ~ & ^ | + << >>

Max ops: 8

Rating: 3

实现思路:

右移取符号填充,然后要求x非零,y为0

实现代码:

int isPositive(int x) {

int y=x>>31;

return (!!x)&(!y);

}

(11) 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

实现思路:

判断x<=y,我们可以做减法。首先计算y-x然后将其右移31位取符号,取y的符号ys,取y^x的值的符号s,然后要求x<=y就必须满足:xy同号并且相减结果为正,或者xy异号,但y为正

实现代码:

int isLessOrEqual(int x, int y) {

//同号相减,异号y为正

int sub=(y+(~x)+1)>>31;

int ys=(y>>31);

int s=(y^x)>>31;

return (!s&!sub)|(s&!ys);

}

(12) ilog2

函数功能:计算x对2的对数并且向下取整

实现要求:

ilog2 - return floor(log base 2 of x), where x > 0

Example: ilog2(16) = 4

Legal ops: ! ~ & ^ | + << >>

Max ops: 90

Rating: 4

实现思路:

采用二分的方法来进行处理,首先选择中间的第16位,得到结果的逻辑值乘以16,然后处理logs+8右移8位乘以8.一次类推直到为1

实现代码:

int ilog2(int x) {

int logs=(!!(x>>16))<<4;

logs=logs+((!!(x>>(logs+8)))<<3);

logs=logs+((!!(x>>(logs+4)))<<2);

logs=logs+((!!(x>>(logs+2)))<<1);

logs=logs+(!!(x>>(logs+1)));

return logs;

}

(13) float_neg

函数功能:返回一个unsigned表示浮点数的负数

实现要求:

float_neg - Return bit-level equivalent of expression -f for

floating point argument f.

Both the argument and result are passed as unsigned int’s, but

they are to be interpreted as the bit-level representations of

single-precision floating point values.

When argument is NaN, return argument.

Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while

Max ops: 10

Rating: 2

实现思路:

浮点数的负数实现很久暗淡,但是需要注意的是对于一个浮点数,他可能是nan,也可能是正负无穷大,也可能是一个可以正常表示的浮点数。对于nan,我们需要直接返回这个值,否则取反符号位。

实现代码:

unsigned float_neg(unsigned uf) {

unsigned int a=0xff;

unsigned int b=1<<31;

unsigned int exp=(uf>>23)&a;//取出阶码

unsigned int frac=uf&0x7fffff;//去除尾数

if(!(exp^a)&&frac) return uf;//当nan,返回uf否则返回-uf

return uf^b;

}

(14) float_i2f

函数功能:返回一个int数据强制转换位浮点数的unsigned类型表示

实现要求:

float_i2f - Return bit-level equivalent of expression (float) x

Result is returned as unsigned int, but

it is to be interpreted as the bit-level representation of a

single-precision floating point values.

Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while

Max ops: 30

Rating: 4

实现思路:

首先我们判断是否为0,如果是那么直接返回。否则计算阶的值exp,如果exp小于等于23,说明可以正常表示,我们只需将尾数左移23-exp即可。如果exp>23,则发生位的截取,这个时候我们要判断是四舍五入还是向偶数取整。我们可以在截取位置加上1。之后我们判断以前的截取位置,如果不为1,我们减去1,如果是四舍五入产生的那么因为减法的借位是不会影响到frac的,如果是向偶数舍入也不会影响。最后我们将exp加上这个尾数,处理有可能产生的向exp进位,然后返回和并值。

实现代码:

unsigned float_i2f(int x) {

if(!x) return 0;//为0返回

else{

int exp=~0;//阶初始化为-1

unsigned temp1=x;

unsigned temp2,temp3;

int shift;

int sign=0x80000000&x;

if(sign) temp1=-temp1;

temp3=temp2=temp1;

while(temp1){

exp=exp+1;

temp1=temp1>>1;

}

shift=23-exp;//计算要移位的长度

if(shift>=0) temp3=temp3<<shift;//shift为正,表示可以用23位表示

else//否则发生截取,考虑舍入

{

shift=-shift;

temp2=temp2>>shift;//右移shift位

temp3+=(1<<(shift-1));//加上低位的进位

if(!(temp2&1)) temp3+=-1;//如果最低位不为1,说明无法发生偶数进位,所以减去1。如果四舍五入,则不会借位成功舍入,否则不发生进位

temp3=temp3>>shift;//右移shift

}

exp=((exp+0x7f)<<23)+(temp3>>1);//加上temp3可能发生向exp的进位

exp=exp&0xff800000; //清零frac

temp3=temp3&0x7fffff;//取后23位

return sign|exp|temp3;}//合并

}

(15) float_twice

函数功能:返回一个unsigned表示的浮点数*2的结果

实现要求:

float_twice - Return bit-level equivalent of expression 2*f for

floating point argument f.

Both the argument and result are passed as unsigned int’s, but

they are to be interpreted as the bit-level representation of

single-precision floating point values.

When argument is NaN, return argument

Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while

Max ops: 30

Rating: 4

实现思路:

这个函数实现并不复杂,我们首先对数据进行分类,如果数据是一个nan或者是无穷大,那么我不能改变它的值,直接返回,否则要判断数据是不是非规格化数,如果是那么将尾数位左移1位,如果是规格化数,我们可以直接将exp+1,但是需要注意的是如果因为exp+1产生了exp=0xff,那么结果因该是无穷大而不是nan,所以这种情况下我们要将frac尾数清零。最后注意合并。

实现代码:

unsigned float_twice(unsigned uf) {

unsigned int s=uf&0x80000000;

unsigned int exp=uf&0x7f800000;

unsigned int frac=uf&0x7fffff;

if(exp==0x7f800000)//Nan and inf

{

return uf;

}

else if(!exp)//非规格化数

{

frac<<=1;

}

else//规格化数,直接exp+1,同时如果exp全1那么需要对frac清零防止nan

{

exp+=(1<<23);

if(exp==0x7f800000) frac=0;

}

return (s|exp|frac);

}

实验结果及分析:

(1) 输入:命令./dlc bits.c和./dlc -e bits.c查看语法错误并检测操作符消耗:

在这里插入图片描述

(2) 编译并执行程序:输入命令make btest编译,指令./btest执行:

在这里插入图片描述

结果分析:

编译之后,我们的15个函数的操作符资源消耗分别为4,3,7,35,5,1,8,7,2,5,13,27,8,27,11满足程序的设计要求,并且通过编译,无警告和错误。运行之后各项得分分别为1,2,3,4,4,1,2,2,2,3,3,4,2,4,4。最后得分为41.程序设计满足实验要求。

收获与体会:

本次实验,我做了大概有一个下午吧,有疑问,有难过当然更有收获也有惊奇,当把我们学过的与运算通过摩根定律转换时,体会到了知识的相通性。取指定字节是,由于一个字节有8位,故实际要移动n<<3位,然后,再让原来的x向右移位,机科取出相应的字节。逻辑右移的过程中要注意消除符号位,所以右移的过程中先凑出来一个0000,然后与x相与即可得到逻辑右移。计算二进制1的过程较为巧妙,刚开始用的while循环,然后,每次让x向右移位,当然了这样会在成超时,于是乖乖用二分法,先找出2位中的1,然后4中的1,接着8位中的1。最后,是int转为unsigned ,以及unsigned转为float*2 要做的都是把它转为规格化数,否则要判断数据是不是非规格化数,如果是那么将尾数位左移1位。总之,在遇到问题的时候,不要害怕问题,要多去尝试寻找解决方法,也就能达到解决问题的目的
图片转存中…(img-tFs7GaeK-1618330307679)]](https://imgtu.com/i/cy27RJ)

结果分析:

编译之后,我们的15个函数的操作符资源消耗分别为4,3,7,35,5,1,8,7,2,5,13,27,8,27,11满足程序的设计要求,并且通过编译,无警告和错误。运行之后各项得分分别为1,2,3,4,4,1,2,2,2,3,3,4,2,4,4。最后得分为41.程序设计满足实验要求。

收获与体会:

本次实验,我做了大概有一个下午吧,有疑问,有难过当然更有收获也有惊奇,当把我们学过的与运算通过摩根定律转换时,体会到了知识的相通性。取指定字节是,由于一个字节有8位,故实际要移动n<<3位,然后,再让原来的x向右移位,机科取出相应的字节。逻辑右移的过程中要注意消除符号位,所以右移的过程中先凑出来一个0000,然后与x相与即可得到逻辑右移。计算二进制1的过程较为巧妙,刚开始用的while循环,然后,每次让x向右移位,当然了这样会在成超时,于是乖乖用二分法,先找出2位中的1,然后4中的1,接着8位中的1。最后,是int转为unsigned ,以及unsigned转为float*2 要做的都是把它转为规格化数,否则要判断数据是不是非规格化数,如果是那么将尾数位左移1位。总之,在遇到问题的时候,不要害怕问题,要多去尝试寻找解决方法,也就能达到解决问题的目的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

savkACUNCB: IOnjn

欢迎来到我的世界

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值