作者:汪晨旸
本次实验由15道题目组成,实验报告将主要记录做题思路。
1.bitNor
/*
* bitNor - ~(x|y) using only ~ and &
* Example: bitNor(0x6, 0x5) = 0xFFFFFFF8
* Legal ops: ~ &
* Max ops: 8
* Rating: 1
*/
int bitNor(int x, int y) {
return (~x)&(~y);
}
德摩根律。
2.copyLSB
/*
* copyLSB - set all bits of result to least significant bit of x
* Example: copyLSB(5) = 0xFFFFFFFF, copyLSB(6) = 0x00000000
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 5
* Rating: 2
*/
int copyLSB(int x) {
return ~(1&x)+1;
}
首先取最低位,然后根据1的补码每一位都是1,0的补码每一位都是0性质完成需求。
3.isEqual
/*
* isEqual - return 1 if x == y, and 0 otherwise
* Examples: isEqual(5,5) = 1, isEqual(4,5) = 0
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 5
* Rating: 2
*/
int isEqual(int x, int y) {
return !(x^y);
}
异或的定义。
4.bitMask
/*
* bitMask - Generate a mask consisting of all 1's
* lowbit and highbit
* Examples: bitMask(5,3) = 0x38 00111000
* Assume 0 <= lowbit <= 31, and 0 <= highbit <= 31
* If lowbit > highbit, then mask should be all 0's
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 16
* Rating: 3
*/
int bitMask(int highbit, int lowbit) {
int lowmask=(1<<lowbit)+(~0);
int highmask=(1<<highbit<<1)+(~0);
return (lowmask^highmask)&highmask;
}
(1«lowbit)+~0是为了构造一个lowbit-1位到0位都是1的mask,(1«highbit«1)+(~0)构造highbit到0位都是1的mask,两个mask异或一下就可以得到答案了。
1«highbit«1而不是1«(highbit+1)是防止highbit=31时,1«32=1
最后&highmask是为了防止highbit<lowbit,如果highbit<lowbit,由于现在异或的结果是lowbit-1位到highbit+1位都是1,&highmask正好为0,反之不会产生影响。
5.bitCount
/*
* 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) {
//0b mask1=0101```,mask2=00110011,mask3=00001111 0000000011111111
int mask1=0x55;
int mask2=0x33;
int mask3=0x0f;
int mask4=0xff;
int mask5=~0+(1<<16);
mask1=(mask1<<8)|mask1;
mask1=(mask1<<16)|mask1;
mask2=(mask2<<8)|mask2;
mask2=(mask2<<16)|mask2;
mask3=(mask3<<8)|mask3;
mask3=(mask3<<16)|mask3;
mask4=(mask4<<16)|mask4;
x=(x&mask1)+((x>>1)&mask1);
x=(x&mask2)+((x>>2)&mask2);
x=(x&mask3)+((x>>4)&mask3);
x=(x&mask4)+((x>>8)&mask4);
x=(x&mask5)+((x>>16)&mask5);
return x;
}
观察一下每个二进制数。例如0b 11101100这个二进制数,每一位上的位不仅表示一个数值,并且表示了这一位数上的数字是否为1。所以bitCount的实现方法就是把每一位加起来即可。
为了使代码优雅一点,我们采取分治的思想。首先,每两个数一组,相加并为一组,得到(还是以上面那个二进制数为例)10 01 10 00 ,然后每两组之间再相加并为一组,依次类推,直到32位都并为一组,就是最后的答案了。
由于两个长为x的二进制数相加结果一定能用长为2*x的二进制数表示,所以不必考虑进位的问题。
6.TMax
/*
* TMax - return maximum two's complement integer
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 4
* Rating: 1
*/
int tmax(void) {
return ~0+(1<<31);
}
造0x7FFFFFFF就好。
7.isNonNegative
/*
* isNonNegative - return 1 if x >= 0, return 0 otherwise
* Example: isNonNegative(-1) = 0. isNonNegative(0) = 1.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 6
* Rating: 3
*/
int isNonNegative(int x) {
return !(x>>31);
}
把符号位提取出来取反即可。
8.addOK
/*
* addOK - Determine if can compute x+y without overflow
* Example: addOK(0x80000000,0x80000000) = 0,
* addOK(0x80000000,0x70000000) = 1,
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 20
* Rating: 3
*/
int addOK(int x, int y) {
return (!(((x+y)^x)>>31))|(((x^y)>>31)&1);
}
首先,溢出的先决条件是x,y同号,即若(sign)x^y=1,则肯定不溢出。
之后,在已知x,y同号的条件下算一下x+y是否与x(或y)异号,异号的话就发生了溢出。
9.rempwr2
/*
* rempwr2 - Compute x%(2^n), for 0 <= n <= 30
* Negative arguments should yield negative remainders
* Examples: rempwr2(15,2) = 3, rempwr2(-35,3) = -3
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 20
* Rating: 3
*/
int rempwr2(int x, int n) {
int mask=(~0)<<n;
int ans=x&(~mask);
return ans+(((x&(~ans+1))>>31)&mask);
}
这个题目对负数的要求很奇怪,按照我的测试题目要求应该是负数直接取低 n 位,前面补 1(低n位正好为0的话前面补0)。所以这题卡了我很久。
首先明确一个概念,对2^n取余,就相当于取低n位数,然后高位补上符号位(取余结果为0则无论正负,都返回0)。 所以先造出一个mask,低n位为0,其余位为1。之后造出一个ans取x的低n位数。 最后,由于负数取余还有一个特殊条件,就是如果取余后结果正好为0,则前面补0,即返回0,所以利用所有正数的算术补码都是负数,符号位为1,0的补码是0的性质,用x&(~ans+1)让取余结果为0的负数ans前面也补0.
事实上,在整理完后我发现,这一题遇到负数先把负数变成正数,然后取余,最后再变回负数跑出来也是满分的。你们可以试试。
10.isLess
/*
* isLess - if x < y then return 1, else return 0
* Example: isLess(4,5) = 1.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 24
* Rating: 3
*/
/*x<y y-x>0 te pan fu hao*/
int isLess(int x, int y) {
int s_x=(x>>31)&1;
int s_y=(y>>31)&1;
int diff=y+~x+1;
return !!diff&(!(s_y&!s_x))&((!s_y&s_x)|(!((diff>>31)&1)));
}
判断x<y,即判断y-x>0,即计算y-x判断符号位。
首先,特判y-x=0的情况,出现代表y=x,返回0;
之后,注意加法溢出的情况,注意到本题只有x,y一正一负的时候才会溢出,故特判x正y负返回0,x负y正返回1; 最后判断符号位,为0返回1,为1返回0。
(写完发现自己有点问题,其实可以判断x-y<0,这样符号位就不用特判0了,符号位为1直接是一个完整的情况)
11.absVal
/*
* absVal - absolute value of x
* Example: absVal(-1) = 1.
* You may assume -TMax <= x <= TMax
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 10
* Rating: 4
*/
int absVal(int x) {
return (x^(x>>31))+!!(x>>31);
}
题目本质上是如果x是正数就不变,x为负数取反加1(取补码)。
注意到任何位与0异或等于它本身,与1异或代表取反,故x^(x»31)满足取反的要求。
!!(x»31)就是满足根据符号位加一的需求了。
12.isPower2
/*
* isPower2 - returns 1 if x is a power of 2, and 0 otherwise
* Examples: isPower2(5) = 0, isPower2(8) = 1, isPower2(0) = 0
* Note that no negative number is a power of 2.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 20
* Rating: 4
*/
int isPower2(int x) {
return !!x&!(x>>31)&(!((x&(~x+1))^x));
}
观察发现如果一个正数是2的幂,则这个数的2进值位只有一个1。负数按照题目要求,都不是2的幂。
故首先判断这个数是否为负(主要是0x8000000在捣乱),之后判断这个数与它的lowbit(取最低位1,一个数与上它的算术补码就是取最低位运算)是否相等,是的话就返回一。值得注意的是,0也与它的lowbit相等,故需特判。
13.float_neg
/*
* 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
*/
unsigned float_neg(unsigned uf) {
unsigned exp=(uf<<1)>>24;
unsigned frac=(uf<<9)>>9;
if(exp==255 && frac) return uf;
return uf^(1<<31);
}
根据要求,NaN返回自身,故特判一下。
之后把符号位取反就行了。
14.float_half
/*
* float_half - Return bit-level equivalent of expression 0.5*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
*/
unsigned float_half(unsigned uf) {
unsigned sign=uf&(1<<31);
unsigned exp=(uf<<1)>>24;
unsigned frac=(uf<<9)>>9;
unsigned round=!((uf&3)^3);
if(exp==255) return uf;
if(exp>1){
exp-=1;
}
else if(exp==1){
exp=0;
frac=((frac>>1)|(1<<22))+round;
}else{
frac=(frac>>1)+round;
}
return sign|(exp<<23)|frac;
}
首先为了避免麻烦(其实主要是不在开头定义变量会报错),先判断进位。由于除二至多会丢弃一位frac,根据Round-To-Even原则,只有粘滞位为1且近似位为1的时候,才会加一。所以直接判断可能会产生Round的末两位是不是11,是的话round=1。
之后,判断uf是否为NaN或无穷,是的话直接丢回去就好了。
最后,根据/2之后的结果为denormal、不/2的时候是否为denormal分成三类,然后对相应的情况进行右移就好了。
15.float_i2f
/*
* 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
*/
unsigned float_i2f(int x) {
unsigned sign=x&(1<<31);
unsigned exp=0;
unsigned frac=0;
unsigned y= x>0?x:-x;
unsigned yy=y;
int index=0;
if(!x) return 0;
while(y>0){
y=y>>1;
index++;
}
exp=index-1+127;
yy= yy<<(32-index);
frac= (yy>>8)& 0x7fffff;
yy= yy&0xff;
if(yy>128||(yy==128&&(frac&1))){
frac+=1;
}
if(frac>>23){
frac-=(1<<23);
exp+=1;
}
return sign|(exp<<23)|frac;
}
首先确定x的正负,然后取x的绝对值,并转为unsigned方便右移操作。
之后特判一下0,因为0会使exp变为126,而正确的指数表达应该指数位为0。
然后判断x的二进制最高位是第几位,借此确定exp(注意要减一和加bias)。
再然后为了统一,将x的最高有效位移到最高,分离出要丢弃的粘滞位(八位,因为frac是23位,再加上一个隐藏的1(已经确定x不为0,所以肯定有这个隐藏1),32-24=8)和保留的位。
最后根据Round-To-Even原则与round-nearest原则,看是否需要进位。值得注意的是如果frac因为进位大于23位,需要将溢出的那一位加到指数上。
(frac= (yy»8)& 0x7fffff; 事实上不用& 0x7fffff,它本身就是无符号数)
说明
欢迎关注作者的csdn博客某汪922,后期会继续更新有关内容。
原文链接:http://t.csdnimg.cn/OHr5Q