Datalab
1.bitXor
-
Ops:7
-
设计思路:
- 由于异或运算的结果是相同取0,相异取1
- 两个数相同的方式有2种:同为1 或 同为0
- 计算 x&y 和 ~x&~y
- 上面2个式子只有2个数不同的情况下,才均为0
- 所以将其分别取反,再做与操作
-
源代码
int bitXor(int x, int y) { return (~(~x&~y)&~(x&y)); }
2.evenBits
-
Ops: 4
-
设计思路:
- 目标是返回0x55555555
- 只能创建8个bit的数字,故int k = 0x55
- 将k左移8位得到0x5555
- 再将其左移16位得到答案
-
源代码
int evenBits(void) { int k = 0x55; k = k<<8|k; return k<<16|k; }
3.fitsShort
-
Ops: 4
-
设计思路:
- 考虑到如果x可以表示为16—bit的2进制补码,则其31—15位数字全部都为1或者0
- 先将x右移15位,将15位以下的内容全部移除
- 由于int是32个bit再将ans向右移动16位,使其每个bit均为最高位,所以此时其每位要么均为1要么均为0
- 通过异或操作判断是否ans是否每个位置都是1或都是0
- 如果均为1或均为0,结果为0,逻辑非以后得到1
-
源代码:
int fitsShort(int x) { int ans = x>>15; return !((ans>>16)^ans); }
4.isTmax
-
Ops:6
-
设计思路:
- Tmax的特点是最高位为0,剩下位均为1
- 观察发现 x+x+2得0
- 而满足x+x+2得0的式子的数还有-1(0x11111111)
- 所以排除-1的情况下取!即为答案
-
源代码:
int isTmax(int x) { return !((x+x+2)|!(~x)); }
5.fitsBits
-
Ops: 7
-
设计思路:
- 发现规律,如果能够表示的话,n-1位以前的元素都是1或者0
- n+~1+1是为了得到n-1
- 用异或来判断是否都为1或都为0
-
源代码:
int fitsBits(int x, int n) { x = x>>(n+~1+1); return !((x>>n)^x); }
6.upperBits
-
Ops: 7
-
设计思路:
- 如果n=0,返回0;如果n!=0,将前n位重置为1,再返回该值
-
源代码:
int fitsBits(int x, int n) { x = x>>(n+~1+1); return !((x>>n)^x); }
7.allOddBits
-
Ops: 7
-
设计思路:
- 根据题意 allOddBits = 0xAAAAAAAA,故先构造此数
- 判断x的偶数位是否都为1
- x&a将x只留下偶数位上的信息
- 再与a异或后取否 判断是否均相同
-
源代码:
int allOddBits(int x) { int a = 0xAA; a = a|a<<8; a = a|a<<16; return !((x & a)^a); }
8.byteSwap
-
Ops: 16
-
设计思路:
- 首先将第m和n个byte提取出来
- 由于一个byte是4个,所以将m和n乘8
- 将x移位后与0xFF取交之后再复位即可将数值提取出来
- 构造不包含m和n位byte的数字
- 将三个式子求和即为结果
-
源代码:
int byteSwap(int x, int n, int m) { int n8 = n << 3; int m8 = m << 3; int a = ((x >> n8) & 0xFF) << m8; int b = ((x >> m8) & 0xFF) << n8; int c = (x & ~(0xFF << m8) & ~(0xFF << n8)); return (a | b | c); }
9.absVal
-
Ops: 5
-
设计思路:
- 分开讨论,如果是非负数其值不变;如果是负数,先取反再加1
- 负数31th bit是1,利用此特性来构造负数时加1
- 利用k^0x00000000 = k、k^0xFFFFFFFF = ~k性质来构造负数取反、非负数不变
-
源代码:
int absVal(int x) { return (x^(x>>31))+((x>>31)&1); }
10.divpwr2
-
Ops: 7
-
设计思路:
- 分类讨论:如果是正数直接移n位,如果是负数的话,由于编码方式不同需要修正结果
- 对于负数而言,如果是偶数不影响结果,如果是奇数,结果会比正确结果小
- 构造[0,n-1]区间全为1的数
- 如果输入是负数就加上这个修正值
-
源代码:
int divpwr2(int x, int n) { return (x+(x>>31&((1<<n)+~0)))>>n; }
11.leastBitPos
-
Ops: 3
-
设计思路:
- ~x+1将所求的x中是1的位中权重最小的那个位以外的所有位取反了
- 所以(~x+1)&x为答案
-
源代码:
int leastBitPos(int x) { return (~x+1)&x; }
12.logicalNeg
-
Ops: 6
-
设计思路:
- 分类讨论:0和非0数
- 0的最高位为0,而非零数和其相反数的最高位必然一个为0、一个为1
- 将x转化为相反数:~x+1
- x|~x+1的结果中只有x=0会使其最高位为0
- 故当最高位是0时返回1,最高位是1时返回0
-
源代码:
int logicalNeg(int x) { return ~((x|(~x+1))>>31)&1; }
13.bitMask
-
Ops: 7
-
设计思路:
- 根据题意将所需的bit全部置为1就好了
- 由于题目要求当lowBit>highBit的时候返回0,故考虑将小于lowBit置为0以及大于highBit置为0
- 将0xFFFFFFFF左移lowbit,将0xFFFFFFFF+(1<<(highbit+1))
- 将2个式子取交便为答案
-
源代码:
int bitMask(int highbit, int lowbit) { return ((~0)<<lowbit)&((~0)+(1<<highbit<<1)); }
14.isLess
-
Ops: 10
-
设计思路:
- 注意到如果两个数字正负性相同,只需要比较两个数字二进制的大小
- 而在正负性不同的情况下,正数大于负数
- 计算出x-y,利用-y=~y+1,即m=x-y
- 用x^y来看符号位是否相同
- m&~yihuo来看若是相同符号情况下x-y的符号
- x&yihuo用来看符号不同时x的符号
- 因此上面两个式子相加后符号位就是答案
-
源代码:
int isLess(int x, int y) { int yihuo = x ^ y; int m = x + ~y + 1; return (((m & ~yihuo) + (x & yihuo)) >> 31) & 1 ; }
15.logicalShift
-
Ops: 8
-
设计思路:
- 题目要求用算术右移实现逻辑右移
- 考虑到算术右移时补充的是符号位,而逻辑右移只会补充0
- 因此只需要将右移后补充的位全部与0取交集就好,同时为了保证其它位不变,其他位应与1取交
- 1<<(32+~n)<<1是为了防止左移32位出现未定义的行为
-
源代码:
int logicalShift(int x, int n) { int m = (~0)+(1<<(32+~n)<<1); return (x>>n)&m; }
16.satMul2
-
Ops: 10
-
设计思路:
- 分类讨论,在没有溢出的情况下,直接输出x>>1,溢出的话
- 用x*2和x的符号位的异或来判断是否溢出:相同不溢出,相异则溢出
- 溢出的话要判断是正溢出还是负溢出:这由x*2的符号位决定
- 用掩码overflow_mask来表示是否越界
- 发现~Tmin = Tmax,所以利用Tmin和2*x的符号位来构造Tmin或者Tmax
-
源代码:
int satMul2(int x) { int x_mul_2 = x << 1; int overflow_mask = (x_mul_2 ^ x) >> 31; int tmin = 1 << 31; int x_mul_2_is_neg = x_mul_2 >> 31; return (~overflow_mask & x_mul_2) | (overflow_mask & (tmin ^ (x_mul_2_is_neg))); }
17.subOK
-
Ops: 10
-
设计思路:
- t1和t2分别是x和y的符号位
- 如果符号位相同做减法一定不会溢出
- 如果符号位不同,可能溢出,也可能不溢出
- 取cf为x-y的符号位
- 如果x-y会溢出其符号位为0,不溢出则为1
- 利用0xFFFFFFFF + 1 = 0构造返回结果
-
源代码:
int subOK(int x, int y) { int t1 = x >> 31; int t2 = y >> 31; int t = t1 ^ t2; int cf = (x + (~y + 1)) >> 31; return (t & (t1 ^ cf)) + 1; }
18.bang
-
Ops: 6
-
设计思路:
- 由于~0 + 1 = 0
- 因此只有当小x=0时,x|~x+1 = 0
- 特别:只有此时其结果的符号位为0
-
源代码:
int bang(int x) { return ~((x|(~x+1))>>31)&1; }
19.bitParity
-
Ops: 11
-
设计思路:
- 考虑到如果有奇数个0,那么必然有奇数个1,反之,有偶数个0必然有偶数个1
- 将32位依次做异或操作
- 偶数个1的话结果为0,奇数个1的话结果为1
- 使用如下方法,每次将答案保存在低位,每一次可以计算一半的位数
-
源代码:
int bitParity(int x) { x = x ^ (x >> 16); x = x ^ (x >> 8); x = x ^ (x >> 4); x = x ^ (x >> 2); x = x ^ (x >> 1); return x & 1; }
20.isPower2
-
Ops: 10
-
设计思路:
- 题目要求只有正数可以满足要求,因此在考虑x的位中只有一个1的时候要排除掉负数
- 另外,注意到满足要求的x有如下性质:x&(x-1) = 0
- 并且发现0也具有该性质,所以我们需要排除0和0x80000000的影响
- 对于0x80000000我们可以利用符号位排除,对于0 可以用!!来排除
- 于是用(~(x>>31)&(!!x))来矫正答案
-
源代码:
int isPower2(int x) { int ret = ((!(x&(x+~0))) & ((~(x>>31)&(!!x)))); return ret; }
来源:CSDN
作者:甘木甘木
链接:https://blog.csdn.net/weixin_44110392/article/details/104119327