实验环境:Clion + WSL2 UBuntu 20.04
1. bitXor
此函数求x和y的异或值,只能使用~和&。考虑到执行异或操作得1的情况(1 ^ 0 = 1,0 ^ 1 = 1),而与操作得1的情况只有1 & 1 = 1,所以 x&y 只有两数都是1的位结果是1,而异或需要的各位不相同的情况在与操作结果的0里,所以在此将x&y的结果取反。而此时取反后,为1的值中还有0&0的结果,所以要考虑将此去除掉。和前面的想法相同,如果获得 ~( ~x & ~y)则会得到 1 & 1的结果。此时这两个结果中共同为1的是x和y中都是1的情况,不同的分别是 0 & 0 和 1 & 1的情况,所以将两者进行与操作,即可得到异或值
/*
* bitXor - x^y using only ~ and &
* Example: bitXor(4, 5) = 1
* Legal ops: ~ &
* Max ops: 14
* Rating: 1
*/
int bitXor(int x, int y) {
return ~(x & y) & ~(~x & ~y);
}
2. tmin
负数为补码,最小的数为1000 0000 0000 0000 0000 0000 0000 0000(-2147483648),根据定义编码如下
int tmin(void) {
return 1 << 31;
}
3.isTmax
用异或来判断等于!((~(x+1)^x)) 判断这个是否为1即可判断是否为最大值,这里有一个例外就是x=-1 由于-1=1111 他利用上面的式子判断也符合,故要特判-1 利用!!(x+1) 这个操作-1和最大值并不相同
int isTmax(int x) {
return ! ( ~( x + 1 ) ^ x ) & !!(x + 1) ;
}
4.allOddBits
此题目为判断奇数为是否全为1,如果全为1则返回1,否则返回0。因此只判断x & 0xAAAAAAAA 是否等于 0xAAAAAAAA,由于不能使用 == 号,则使用a == b 等价于 ! (a ^ b)。又因为只能使用0x00-0xff大小的数,因此需要从0xAA进行移位操作进行构造0xAAAAAAAA
int allOddBits(int x) {
int mask = 0xAA;
mask = mask | mask << 8;
mask = mask | mask << 16;
return !((x & mask) ^ mask) ;
}
5.negate
负数编码为补码形式,为原码按位取反+1,因此对于正数变负数的方法为按位取反+1,对于一个负数来说,计算机中存储的是其补码,而补码的补码是原码,而~n+1就是先将负数的补码,变成原码,这个时候在将符号位变为0的过程
int negate(int x) {
return ~x + 1;
}
6.isAsciiDigit
根据题意是要判断0x30-0x39之间的字符,首先判断高位4比特,由于都为0100,则只需要比对是否都为0100即可。观察低位4比特位为0000-1001,最大为0x09,则0x09减去第四位,如果为非负数,则表示在范围内,如果为负数,则表示不在范围内,由于只能使用+号,则将数值取反进行相加进行比较
int isAsciiDigit(int x) {
int first = x >> 4;
int second = x & 0x0f;
return !((first ^ 0x03) | (((0x09 + (~second + 1)) >> 31) ^0x00));
}
7.conditional
本题是使用位运算实现三目运算符,考虑一个数和一个全0的数做按位与运算结果是全0,和一个全1的数进行与运算结果是这个数本身,所以当x为0的时候,应该输出z并且将y屏蔽,则应该是( x & y) | (~x & z)。此时应该考虑x不为0时该如何处理,由上述式子得知,应当将不为0的数统一变为0的反码,及0xffffffff,因此将x与0作比较,并将x转换
int conditional(int x, int y, int z) {
int flag = !(x ^ 0); // x为0的时候,flag = 1
x = ~flag + 1; // flag = 1 的时候,此时x变为0xffffffff,即x此时表示不为0时的状态
return( ~x & y) | (x & z);
}
8.isLessOrEqual
x<=y的判断分为符号相同和符号不同,如果是符号相同,需要判断y-x是否>=0,如果是符号不同,需要判断x和y的符号的差进行求值
ps:右移操作如果最左边为为1,则会填充1,需要&1进行取值
int isLessOrEqual(int x, int y) {
int fx = (x >> 31) & 1; // x的符号
int fy = (y >> 31) & 1; // y的符号
// 符号相同 y - x >= 0 符号不同 fy - fx < 0 为真
return ((!(fx^fy )) & !((y + (~x + 1)) >> 31)) | ((fy + ~fx + 1) >> 31) & 1;
}
9.logicalNeg
除了0与0x80000000这两个数,每个数与其补码的交为0xffffffff,而0和0x8000000这两个数的补码为这个数本身,由于所求的是逻辑非,0返回1,非零返回0,而0和其他数字经过计算后,只有符号位不同,0的符号位0,其余数都为1,所以获得符号位,并且+1控制返回值
int logicalNeg(int x) {
return ((x | (~x + 1)) >> 31 )+ 1 ;
}
10.howManyBits
int howManyBits(int x) {
int sign,b16,b8,b4,b2,b1,b0;
sign = x >> 31;
// 将 x 转换为正数,这样只要判断最高位 1 出现的位置即可
x = (sign & ~x) | (~sign & x);
// 判断高16位是否存在 1,如果有就右移 x
b16 = (!!(x >> 16)) << 4;
x = x >> b16;
// 判断高 8 位是否存在 1,如果有就右移 x
b8 = (!!(x >> 8)) << 3;
x = x >> b8;
// 判断高 4 位是否存在 1,如果有就右移 x
b4 = (!!(x >> 4)) << 2;
x = x >> b4;
// 判断高 2 位是否存在 1,如果有就右移 x
b2 = (!!(x >> 2)) << 1;
x = x >> b2;
b1 = !!(x >> 1);
b0 = x >> b1;
return b16 + b8 + b4 + b2 + b1 + b0 + 1;
}
11. floatScale2
根据浮点数的定义,如果exp=255 并且尾数非0 就是NaN 直接return 就好 其次如果frac 全为0 那么则表示无穷大 这两种情况都可以直接return,如果exp=0 则表示非规格化数,那么我们直接返回uf*2,如果exp!=0 && !=255 那么表示规格化数,那么我们的修改就先把exp+1
unsigned floatScale2(unsigned uf) {
int exp = (uf & 0x7f800000) >>23;
int sign = uf & (1 << 31);
int frac = uf & 0x7fffffff;
if(exp == 0) { return (frac << 1) | sign; }
if(exp == 255) {return uf;}
exp = exp + 1;
return (exp<<23) | (uf & 0x807fffff);
12. floatFloat2Int
如果原浮点值为0则返回0;如果真实指数大于31(frac部分是大于等于1的,1<<31位会覆盖符号位),返回规定的溢出值0x80000000u;如果exp<0,结果为0,则返回0。剩下的情况:首先把小数部分(23位)转化为整数(和23比较),然后判断是否溢出:如果和原符号相同则直接返回,否则如果结果为负(原来为正),否则原来为负,结果为正
int floatFloat2Int(unsigned uf) {
int exp = ((uf & 0x7f800000) >>23) - 127 ;
int sign = (uf >> 31) & 1;
int frac = uf & 0x007fffff;
if(exp < 0) return 0;
else if(exp >= 31) {
return 0x80000000u;
}
else {
frac = frac | (1 << 23);
if(exp < 23) {
frac = frac >> (23-exp);
}else{
frac = frac << (exp-23);
}
}
if(sign) return -frac;
else return frac;
}
13.floatPower2
根据浮点数定义,先算指数,如果指数小于0,则表示值为0,如果大于255,则表示无穷大,如果在这之前,则为2^x的值,为正数且底数为1.000,则只需要将指数移位即可
unsigned floatPower2(int x) {
int exp = 127 + x;
if(exp <= 0) return 0;
if(exp >= 255) return 0xff << 23;
return exp << 23;
}