问题描述

您的目标是修改您的 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<>(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;}