Introduction
1.bitXor(int x, int y)
* bitXor - x^y using only ~ and &
* Example: bitXor(4, 5) = 1
* Legal ops: ~ &
* Max ops: 14
* Rating: 1
思路:可以先将x、y同为1或0的位置找出来并置为0,剩余数置为1。x&y可以表示同为1的位置信息,~x&~y表示同为0的位置信息。那么x^y就是~(x&y)&~(~x&~y)
int bitXor(int x, int y) {
return ~(x&y)&~(~x&~y);
}
2.tmin(void)
* tmin - return minimum two's complement integer
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 4
* Rating: 1
思路:该题为返回最小的二进制补码整数,最小的有符号数,符号位为1,其余都是0。int占4字节,即32位,所以对1左移31位来构造最小补码。
int tmin(void) {
return 1<<31;
}
3.isTmax(int x)
* isTmax - returns 1 if x is the maximum, two's complement number,
* and 0 otherwise
* Legal ops: ! ~ & ^ | +
* Max ops: 10
* Rating: 1
思路:假设x是二进制补码的最大值,(x+1)为1<<31,那么~(x+1)^x就是0,再逻辑否即为1。但是由于 -1 = 0xFFFFFFFF。对其进行加1后,该操作数会被截断,使得结果为0x00000000,每一位刚好也和-1的每一位互补。因此,x = -1的情况是需要特判的。!(x+1) 即为1。 则该式在 x = -1 时一定为真,x != -1 时结局就取决于~(x+1)^x。故为 !(~(x+1)^x|!(x+1))
int isTmax(int x) {
return !((~(x+1)^x)|!(x+1));
}
4.allOddBits(int x)
* allOddBits - return 1 if all odd-numbered bits in word set to 1
* where bits are numbered from 0 (least significant) to 31 (most significant)
* Examples allOddBits(0xFFFFFFFD) = 0, allOddBits(0xAAAAAAAA) = 1
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 12
* Rating: 2
思路: 使用移位运算符构造出奇数位全1的数 y = 0xAAAAAAAA,如果与x相同,y&x就仍为y,然后再进行y^y然后返回其值的逻辑非得到1。若y与x不同,y&x不为y,再^操作后返回逻辑非得到0。
int allOddBits(int x) {
int y = 0xAA + (0xAA << 8);
y = y + (y << 16);
return !((x&y)^y);
}
5.negate(int x)
* negate - return -x
* Example: negate(1) = -1.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 5
* Rating: 2
思路:~x+x=-1;那么-x就为~x+1
int negate(int x) {
return ~x+1;
}
6.isAsciiDigit(int x)
* isAsciiDigit - return 1 if 0x30 <= x <= 0x39 (ASCII codes for characters '0' to '9')
* Example: isAsciiDigit(0x35) = 1.
* isAsciiDigit(0x3a) = 0.
* isAsciiDigit(0x05) = 0.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 15
* Rating: 3
思路:这个函数让我们判断一个数是否位于0x30到0x39之间。分别进行判断,首先判断10位是否为3,我们可以利用右移运算符。然后,判断个位是否小于等于9。判断a小于等于b时,可以通过a + b <= 0来进行判断,也就是让二者相加,然后判断符号位。 y 在 0 到 9 之间,则 y - 10 < 0,由于符号限制,我们通过移位后判断符号位来作为条件3。由于不能用减法,可以通过y+~y=-1达到目的。
int isAsciiDigit(int x) {
int y = x & 0xf; // 把最低位先拿出来
return !((x >> 4) ^ 0x3) & !((0x9 + (~y + 1)) >> 31);
}
7.conditional(int x, int y, int z)
* conditional - same as x ? y : z
* Example: conditional(2,4,5) = 4
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 16
* Rating: 3
思路:x=0时!x就是0x00000001,~(!x)+1为全一,x&z即为z,~x&y为0。x!=0时!x为0,~(!x)+1为全0,x&z为0,~x&y即为所求。
int conditional(int x, int y, int z) {
x = ~(!x)+1;
return (x&z)+(~x&y);
}
8.isLessOrEqual(int x, int y)
* isLessOrEqual - if x <= y then return 1, else return 0
* Example: isLessOrEqual(4,5) = 1.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 24
* Rating: 3
思路:当 y 与 x 同号时,x - y 不会溢出,只需判断x-y的符号。当 y 与 x 异号时,x - y 可能会溢出,这时只分别判断 y 和 x 的符号即可。首先利用移位操作,分别得到 x, y 的符号位,即int signx=(x >> 31) & 1;int signy = (y >> 31) & 1;int flag1=signx&(!signy),
正负 | signx | signy | 返回值flag1 |
x正y负 | 0 | 1 | 0 |
x负y正 | 1 | 0 | 1 |
在判断x-y时利用-y=~y+1;x≤y等价于x<y+1,因此x≤y时x-y-1的符号位为1。首先e用来判断x,y同号,然后((x+~y)>>31)判断符号位。最终flag1|flag2即为所求。
int isLessOrEqual(int x, int y) {
int signx = (x >> 31) & 1;
int signy = (y >> 31) & 1;
int flag1 = signx & (!signy);
int e = signx ^ signy; //判断同号
int flag2 = ((!e) & ((x + ~y) >> 31) & 1);
return flag1 | flag2;
}
9.logicalNeg(int x)
* logicalNeg - implement the ! operator, using all of
* the legal operators except !
* Examples: logicalNeg(3) = 0, logicalNeg(0) = 1
* Legal ops: ~ & ^ | + << >>
* Max ops: 12
* Rating: 4
思路:仍然利用-x=~x+1;若x为0,则 x | (-x) 的符号位为0,将其右移31位依然为0,再+1即为1。若x不为0 则 x | (-x) 的符号位为1,将其右移31位可得到 0b11111...,即-1,再+1即为0。
int logicalNeg(int x) {
return ((x|(~x+1))>>31)+1;
}
10.howManyBits(int x)
* howManyBits - return the minimum number of bits required to represent x in
* two's complement
* Examples: howManyBits(12) = 5
* howManyBits(298) = 10
* howManyBits(-5) = 4
* howManyBits(0) = 1
* howManyBits(-1) = 1
* howManyBits(0x80000000) = 32
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 90
* Rating: 4
思路:原理:对于正数,从高位到低位,找第一个位是1的(比如是n),再加上符号位,则最少需要n+1个位;对于负数,从高位到低位,找第一个位是0的(比如是n),则最少需要n位。int b16, b8, b4, b2, b1, b0;表示0~15、16~23、24~27、28~29、30、31的位置处是否含有1,如有,则对其赋值需要的位数。sign用以取符号位;然后如果x为正则不变,x为负则取反,之后只用找到含有1的位置即可。b16先看高16位是否含有1,若有则表示至少需要16位,所以给b16赋值为16(1 << 4 = 16)。若有1,则原数右移16位,因为上面已经确定是否至少需要16位(针对0~15);若没有1,则b16为0,x不用移位,继续往下面判断。b8看剩余位的高8位是否含有1,若有则表示至少还需要8位,给b8赋值为8。接着同理。最终b16+b8+b4+b2+b1+b0+1(加上符号位)。
int howManyBits(int x) {
int b16, b8, b4, b2, b1, b0;
int sign = x >> 31;
x = (sign&~x)|(~sign&x);
b16 = !!(x >> 16) << 4;//
x = x >> b16;
b8 = !!(x >> 8) << 3;
x = x >> b8;
b4 = !!(x >> 4) << 2;
x = x >> b4;
b2 = !!(x >> 2) << 1;
x = x >> b2;
b1 = !!(x >> 1);
x = x >> b1;
b0 = x;
return b16+b8+b4+b2+b1+b0+1;
}
11.floatScale2(unsigned uf)
* floatScale2 - Return bit-level equivalent of expression 2*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
思路:先取出对应的符号s、尾数frac 和 阶码expr。unsigned s = uf >>31;unsigned expr =(uf >>23)&(0xFF);unsigned frac = uf &0x7FFFFF;分类讨论:(1)若f=0,则frac==0且expr==0,直接return 0。(2)如f为NaN或inifity,则expr ==0xFF,直接返回uf 。(3)expr==0,则frac <<1 并|上符号位s << 31。(4)expr ++ ,return (s<<31) | (expr <<23) | frac。
unsigned floatScale2(unsigned uf) {
unsigned s = (uf >> 31)& 0x1;
unsigned expr = (uf >> 23) & (0xFF);
unsigned frac = uf & 0x7FFFFF;
if(expr ==0 && frac == 0)
return uf;
if(expr == 0xFF)
return uf;
if(expr == 0)
{
frac <<= 1;
return (s << 31) | frac;
}
expr++;
return (s<<31) | (expr << 23) | frac;
}
12.floatFloat2Int(unsigned uf)
* floatFloat2Int - Return bit-level equivalent of expression (int) f
* for floating point argument f.
* Argument is passed as unsigned int, but
* it is to be interpreted as the bit-level representation of a
* single-precision floating point value.
* Anything out of range (including NaN and infinity) should return
* 0x80000000u.
* Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
* Max ops: 30
* Rating: 4
思路:该题为将浮点数转换为整数,若超出范围则返回0x80000000u。先取出对应的符号s、尾数frac 和 阶码expr。unsigned s = uf >>31;unsigned expr =(uf >>23) & (0xFF);unsigned frac = uf & 0x7FFFFF;分类讨论:(1)uf为0,直接返回0。(2)超出范围(Ini / nan),此时expr ==0xFF,直接return 1 << 31。(3)expr == 0,uf<1,同样返回0。(4)首先计算E:int E = expr -127; 和M:frac= frac |(1<<23);若E>31同样超出int范围,return 1<<31。若E<0, M * 2^E <1,return 0若E>=23,则M左移 E-23若E<23,则M右移 23-E。最后若s为1,则取反再+1,否则直接返回M。
int floatFloat2Int(unsigned uf) {
unsigned s = uf >> 31;
unsigned expr = (uf >> 23) & (0xFF);
unsigned frac = uf & 0x7FFFFF;
if(expr == 0 && frac == 0)
return 0;
if(expr == 0xFF)
return 1 << 31;
if(expr == 0)
{
return 0;
}
int E = expr - 127;
frac = frac | (1 << 23);
if(E >31)
return 1 << 31;
else if(E < 0)
return 0;
else if(E >= 23)
{
frac <<= (E - 23);
}
else
{
frac >>= (23 - E);
}
if(s)
return ~frac + 1;
return frac;
}
13.floatPower2(int x)
* floatPower2 - Return bit-level equivalent of the expression 2.0^x
* (2.0 raised to the power x) for any 32-bit integer x.
*
* The unsigned value that is returned should have the identical bit
* representation as the single-precision floating-point number 2.0^x.
* If the result is too small to be represented as a denorm, return
* 0. If too large, return +INF.
*
* Legal ops: Any integer/unsigned operations incl. ||, &&. Also if, while
* Max ops: 30
* Rating: 4
思路:分类讨论:(1)可表示的最小范围是阶码全为0,尾数只有最后一位是1,x<-149即2^-(127+23),则x<-149时,计算结果太小,无法表示,直接返回0。(2)可表示的最大范围是阶码全为1,尾数全为1,即1.11111...(2) * 2 ^(127),对于阶码全为1的情况,直接返回INF,即 return 0xFF << 23。(3)阶码全为0,指数对应为1-127 = -126,可表示的二进制位数就是 x + 126 +23 (此时-149<x<-126),return 1 << (x + 126 + 23)(4) -126<= x <=127的情况,计算阶码 expr = x - 127,return expr << 23 即可。
该题如果显示超时可以通过在driver.pl文件里两个btest相关的命令加上- T 30解决。
unsigned floatPower2(int x) {
if(x < -149)
return 0;
else if(x < -126)
return 1 << (x + 149);
else if(x <= 127)
return (x + 127) << 23;
else
return (0xFF) << 23;
}