计算机系统实验1:数据实验datalab

问题描述

您的目标是修改您的 bits.c 副本,使其通过所有在不违反任何编码准则的情况下在 btest 中进行测试。

实验环境

ubuntu 16.04

实验内容

1、函数bitand
此函数的功能是实现两个数按位相与,由于只能使用|和~,所以考虑德摩根定律将表达式进行变换。

int bitAnd(int x, int y) {
    
    
	return ~((~x)|(~y));
}

2、函数getByte
此函数的功能是从参数x中取第n个字节,思路是:将参数x右移n个字节,此时要取的字节就在最右边,将右移后的数与0xff相与即可。

int getByte(int x, int n) {
    
    
	n=n<<3;
	x=x>>n;
	return x&0xff;
	
}

3、函数logicalShift
此函数的功能是将参数x进行逻辑右移n个bit,注意这里的逻辑右移与算术右移不同的是逻辑右移高位补0,于是对于可能为负数的参数x就需要考虑将其高位变0,思路是将其参数x右移n个bit后,与0000…11111(n个0)相与,即可将高位变0.

int logicalShift(int x, int n) {
    
    
  	return ~(((1<<31)>>n)<<1)&(x>>n);
}

4、函数bitAnd
此函数的功能是返回数的二进制表示中1的个数,思路是使用二分法,先得到mask1对应32位的0101010101…,mask2对应32位的00110011…,mask3对应32位的00001111…,mask4对应32位的0000000011111111…,mask5对应32位的低位全为1。先计算x中每两位中1的个数,用num记录1的个数,以此类推,计算每4位、8位、16位中1的个数,最后整合的结果即为x中1的个数。每次错位就相当于一次相加。

int bitCount(int x) {
    
    
	int num=0;
	int tmpmask1=(0x55)|(0x55<<8);
	int mask1=(tmpmask1)|(tmpmask1<<16);
	int tmpmask2=(0x33)|(0x33<<8);
	int mask2=(tmpmask2)|(tmpmask2<<16);
	int tmpmask3=(0x0f)|(0x0f<<8);
	int mask3=(tmpmask3)|(tmpmask3<<16);
	int mask4=(0xff)|(0xff<<16);
	int mask5=(0xff)|(0xff<<8);
	num=(x&mask1)+((x>>1)&mask1);
	num=(num&mask2)+((num>>2)&mask2);
	num=(num+(num>>4))&mask3;
	num=(num+(num>>8))&mask4;
	num=(num+(num>>16))&mask5;
	return num;
}

5、函数bang
此函数的功能是实现逻辑取反操作,对于非零数取反输出0,零取反输出1.思路是先将数与其相反数相或,如果参数是零则这里得到的结果是全0,如果参数是非零数得到的结果只有两种情况,要么是全1,要么是0x80000000。再将得到的数向右移31位后按位取反,对于0得到的结果是全0,而对于非零数得到的结果是全1,最后返回与1相与的结果即可。

int bang(int x) {
    
    
	int temp=x|(~x+1);
	temp=~(temp>>31);
	return (temp&1);
}

6、函数tmin
此函数的功能是返回32位最小的二进制补码整数,也就是0x80000000,直接将1左移31位即可。

int tmin(void) {
    
    
  return (1<<31);
}

7、函数fitBits
此函数的功能是判断参数x能否用n位的二进制补码进行表示,即等同于判断x是否在-2(n-1)与2(n-1)-1之间。考虑将其分为两种情况,如果在范围内,将其向右移动n-1位后,加1再移位得到的结果应该是0,而如果不在范围内那么按照上述的操作得到的结果就应该是1,再将所得结果取反即可。

int fitsBits(int x, int n) {
    
    
 	return !(((x>>(n+(~0)))+1)>>1);
}

8、函数divpwr2
此函数的功能是计算x/(2n),思路是将x分情况讨论,当x为正数的时候可以直接移n位就能得到x/(2n),但是对于负数情况有所不同,负数的移位操作是向负取整,而本题中是需要向0取整,于是考虑对于负数加一个偏移量,使它加上偏移量后能直接移位得到目标值。

int divpwr2(int x, int n) {
    
    
	int sign=x>>31;
	int mask=(1<<n)+(~0);
	return (x+(sign&mask))>>n;
}

9、函数negate
此函数的功能是返回相反数,根据补码中相反数的计算方法,按位取反后加一即可。

int negate(int x) {
    
    
	return ((~x)+1);
}

10、函数ispositive
此函数的功能是判断x是否为正。思路是将数分为两种情况,一种是为0,另一种情况是不为0。当不为0时,将数右移31位,如果是正数这样会得到全0,如果是负数得到全1;当为0,函数返回0。

int isPositive(int x) {
    
    
	return !((x>>31)|(!x));
}

11、函数isLessOrPositive
此函数的功能是判断x<=y是否为真。这里不能仅仅判断x-y的值,因为可能存在溢出,所以需要分情况讨论。首先是两个数异号的情况,这种情况我们使用表达式(!signy)&signx刚好可以表示结果;其次是两个数同号的结果,这时我们判断两个数相减结果的符号即可,最后就是两个数相等的情况,这种情况只需要看两数亦或结果。将上述三种情况亦或即可满足要求。

int isLessOrEqual(int x, int y) {
    
    
	int signx=(x>>31)&1;
	int signy=(y>>31)&1;
	int sign=(!signy)&signx;
	int tmp=x+((~y)+1);
	tmp=((tmp>>31)&1)&(!(signx^signy));
	return (sign|tmp|((!(x^y))));
}

12、函数ilog2
此函数的功能是将x取对数。思路也是采用分治法,先将32位长度处理为16位长度,(!!(x>>16))<<4实现了当x大于2^16时,先将16记录下来(1<<4),否则这一步就是0,之后bitsNumber+((!!(x>>(bitsNumber+8)))<<3),当x大于16时,记录下来的bitsNumber同样再加上去掉后16+8位之后的数字,这样对前一半16位再进行处理,依次循环下去,否则当bitsNumber小于16时,处理的是后16位的后8位,依次类推,得到最终结果。

int ilog2(int x) {
    
    
	int bitsnumber=0;
	bitsnumber=(!!(x>>16))<<4;
	bitsnumber=bitsnumber+((!!(x>>(bitsnumber+8)))<<3);
	bitsnumber=bitsnumber+((!!(x>>(bitsnumber+4)))<<2);
	bitsnumber=bitsnumber+((!!(x>>(bitsnumber+2)))<<1);
	bitsnumber=bitsnumber+(!!(x>>(bitsnumber+1)));
	return bitsnumber;
}

13、函数float_neg
此函数的功能是返回浮点数的相反数,注意考虑结果为NaN的情况,题目中有说明,如果结果为NaN,则返回原值。`

unsigned float_neg(unsigned uf) {
    
    
	unsigned t=uf&0x7fffffff;
	if(t>0x7f800000)
	return uf;
	return uf^(1<<31);
}

14、函数float_i2f
此函数的功能是返回整型变量x的浮点数的二进制形式,返回整型变量x的浮点数的二进制形式。当x=0时,返回0,当x小于0时,取sign为1000…,absX为其绝对值。绝对值不断左移,shiftLeft记录左移位数,直至最高位为1为止,afterShift为左移后的结果。 0x01ff为111111111,0x0100为100000000, 判断是否需要进位,如果需要,flag为1。 浮点数可以分为三个部分,符号位、阶码、尾数。按无符号整数相加即可。

unsigned float_i2f(int x) {
    
    
	unsigned shiftleft=0;
	unsigned aftershift, tmp, flag;
	unsigned absx=x;
	unsigned sign=0;
	if(x==0)
	return 0;
	if(x<0){
    
    
	sign=0x80000000;
	absx=-x;
	}
	aftershift=absx;
	while(1)
	{
    
    
	tmp=aftershift;
	aftershift=aftershift<<1;
	shiftleft++;
	if(tmp&0x80000000)
	break;
	}
	if((aftershift&0x01ff)>0x0100)
	flag=1;
	else if((aftershift&0x03ff)==0x0300)
	flag=1;
	else flag=0;
	return (sign+(aftershift>>9)+((159-shiftleft)<<23)+flag);
}

15、函数float_twice
此函数的功能是返回浮点数乘以2的结果,如果阶码全为0,则考虑符号位,并将其右移。如果阶码并不是全为1,则将阶码加1,其他情况不必处理,直接返回。

unsigned float_twice(unsigned uf) {
    
    
	unsigned f=uf;
	if((f&0x7f800000)==0){
    
    
	f=((f&0x007fffff)<<1)|(0x80000000&f);
	}
	else if((f&0x7f800000)!=0x7f800000){
    
    
	f=f+0x00800000;
	}
	return f;
}

猜你喜欢

转载自blog.csdn.net/weixin_51295681/article/details/124236312