题目来自CMU的datalab1,解答为笔者原创。
bitXor
int bitXor(int x, int y) {
int t1=~(x&y);
int t2=~((~x)&(~y));
return t1&t2;
}
利用x位与y和反x、反y位与实现位异或。
tmin
int tmin(void) {
return (1<<31);
}
返回最小的整形0x800000000。
isTmax
int isTmax(int x) {
int i=x+1;
x=x+i;
x=~x;
i=!i;
x=x+i;
return !x;
}
如果输入的是最大的整形0x40000000,则前三行首先获得二进制全1的整数,然后利用后两行排除0xffffffff。
allOddBits
int allOddBits(int x) {
int a,b,c;
a=0xAA;
b=(a<<8)+a;
c=(b<<16)+b;
return !(c^(c&x));
}
首先获得奇数位全部唯一的整形c,然后c与x做位与运算取x的奇数位在和c做位异或,最后取反即可得答案。
negate
int negate(int x) {
return ~x+1;
}
利用补码的性质取负。
isAsciiDigit
int isAsciiDigit(int x) {
int co1,co2;
co1=(~0x7)&x;
co2=(~0x1)&x;
return !(co1^0x30)|!(co2^0x38);
}
将0-9的ascii码分为0x30-0x37,0x38-0x39两类。分别去掉x的低3位和低1位,并与0x30/0x38分别做异或运算并取反,如果有输出为1的,即说明x在数字0-9范围内。
conditional
int conditional(int x, int y, int z) {
int w=!x,r;
w=~w+1;
r=((y&(~w))+(w&z));
return r;
}
x等于0或不等于0,分别获得值为1,0的w,然后将y,z分别与w相乘(利用位取反和位与实现)最后输出结果即可得。
isLessOrEqual
int isLessOrEqual(int x, int y) {
int s1,c1,c2,c3,c4,r,sr,s2;
s1=(x>>31)&1,s2=(y>>31)&1;
c1=s1^s2;//same=0,diff=1
c2=s1&c1;//x=minus y=pos out=1 outp=1
c3=!(x^(~x+1));//out1 outp=1
c4=s2&c1;//out1 outp=0
r=y+(~x+1);
sr=(r>>31)&1;//out0 outp=1
return (c2|c3)&(!c4)|((!sr)&(!c1));
}
c1:判断两者符号是否相同。如果不同输出1,相同输出0。
c2:判断是否x为负,y为正,若是则输出1。
c4:判断是否x为正,y为负,若是则输出1。
c3:判断x是否为0xffffffff。
最后通过位或、为与和取反操作实现:
若c2输出1直接输出1,若c3输出1直接输出0;
若c3输出1直接输出1;
最后判断y-x的符号以判断大小。
logicalNeg
int logicalNeg(int x) {
int r=(~x+1)^x,s;
s=(x>>31)&1;
r=r>>31;
return (~(r&1))&1&~s;
}
首先利用x和x的补码做位异或判断是否为0(或0xffffffff),然后判断x的符号以排除0xffffffff的可能。
howManyBits
int howManyBits(int x) {
int sign,t,is0,a,b,c,d,o1,o2,o3,o4,o5,e,f,digit,full,d1,d2,d3;
sign=(x>>31)&1;
t=((~x+1)&((~sign)+1))+(x&(~!sign+1));
is0=(~x+1)^x;is0=!is0;
a=255;a=(a<<8)+a;
b=a<<16;
o1=b&t;o1=!!o1;//out 1 = high 16 digits with num
c=255<<8;
d1=(16&(~o1+1));
c=c<<d1;//test high 8 digits
o2=c&t;o2=!!o2;//out 1 = high 8 digits with num
d=240;
d=d<<d1;
d2=(8&(~o2+1));
d=d<<d2;
o3=d&t;o3=!!o3; //out 1 =high 4 digits with num
e=12;
d3=(4&(~o3+1));
e=e<<(d1+d2+d3);
o4=e&t;o4=!!o4; //out 1 = high 2 digits with num
f=2;
f=f<<d1;
f=f<<d2;
f=f<<d3;
f=f<<(2&(~o4+1));
o5=f&t;o5=!!o5;
digit=d1+d2+d3+(2&(~o4+1))+(1&(~o5+1))+2;
full=t^((1<<digit+~2+1);full=!full;
return digit+~(full&sign)+~(is0&!sign)+2;
}
利用二分法
首先判断x的正负,如果为负,则令x=x的补码。判断x是否为0,是否为0xffffffff,得到is0和x的符号位sign。
判断高十六位是否有1存在 得出逻辑值o1。若有1存在,则将考虑的区间取为高十六位,反之取为低十六位。
然后判断高(八、四、二、一)位是否有1存在,得出逻辑值(o2、o3、o4、o5)。若有1存在,则将考虑的区间取为高(八、四、二、一)位,反之取为低(八、四、二、一)位。
最后将o1,o2,o3,o4,o5乘上16,8,4,2,1相加,加上is0和sign的修正即可得到答案。
floatScale2
unsigned floatScale2(unsigned uf) {
int m=1<<31;
unsigned si,exp,expr,frac;
if(uf==0||uf-m==0)return uf;
si=uf&m;
exp=255;
exp=exp<<23;
expr=exp&uf;
if(expr==exp)return uf;
frac=(~exp)-m;
frac=frac&uf;
if(expr==0) return(si+(frac<<1));
//else if(expr==0) return (si+(frac<<1));
else if(frac==0) return ((expr+(1<<23))&~(1<<31))+si;
else return ((expr+(1<<23)+frac)&~m)+si;
}
首先判断uf是否为0或-0,,若是则返回uf。
然后判断指数部分是否为全1,是则返回uf。
然后判断指数部分是否为0,是则返回小数部分左移一位并加上符号si。
然后判断小数部分是否为0,是则返回指数部分加1在加上符号si。
若都不为零,则返回指数部分加1再加小数部分再加上符号si。
floatFloat2Int
int floatFloat2Int(unsigned uf) {
int si,ex,exp,frac,fracr,result=0;
si=uf&(1<<31);
ex=255<<23;
exp=((ex&uf)>>23);
if(exp==0) return 0;
if(exp==255) return 0x80000000;
exp=exp-127;
frac=~ex-(1<<31);
if(exp>30) return 0x80000000;
if(exp<0) return 0;
fracr=frac&uf;
result=0;
if(exp>=0)
result=1<<exp;
if(exp>23) {
result+=fracr<<(exp-23);
if(si) return -result;
else return result;
}
result+=fracr>>(23-exp);
if(si) return -result;
else return result;
}
首先检测是否超出范围(是否为INF,是否超过int范围,即指数部分超过30)
然后检测是否为非规范数,若是则返回0;
若没有超过范围,则对小数部分左移(指数大于23)exp-23位或右移(指数小于等于23)23-exp位。
最后根据uf的符号返回-result或result。
unsigned floatPower2(int x) {
int INF=255<<23;
int exp=x+127;
if(exp<=0) return 0;
if(exp>=255) return INF;
return exp<<23;
令x+127得到指数部分exp。
首先检测exp是否为0,是则直接返回0。
然后检测exp是否溢出,若是则返回INF。
若exp在正常范围,则返回exp<<23。