满分参考
bitAnd
获取x、y的位与结果
由德摩根律可直接得到答案
/*
* bitAnd - x&y using only ~ and |
* Example: bitAnd(6, 5) = 4
* Legal ops: ~ |
* Max ops: 8
* Rating: 1
*/
int bitAnd(int x, int y) {
return ~((~x)|(~y));//~(AB) = ~A + ~B
}
getByte
获取x的指定字节
可以先将所求字节利用右移移到最低位,然后用掩码提取最低位字节
/*
* getByte - Extract byte n from word x
* Bytes numbered from 0 (LSB) to 3 (MSB)
* Examples: getByte(0x12345678,1) = 0x56
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 6
* Rating: 2
*/
int getByte(int x, int n) {
return (x>>(n<<3))&0xff;
}
logicalShift
实现逻辑右移
由于>>为算术右移,采用符号位补位,因此只需将补位的部分全部变为0即可
于是将x的算术右移结果与一个正的全1掩码的算术右移结果相与即可
/*
* logicalShift - shift x to the right by n, using a logical shift
* Can assume that 0 <= n <= 31
* Examples: logicalShift(0x87654321,4) = 0x08765432
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 20
* Rating: 3
*/
int logicalShift(int x, int n) {
int temp;
x = (x>>n);
temp = ~(1<<31);//0x7fffffff
temp = ((temp>>n)<<1)|1;
return x&temp;
}
bitCount
统计x中所有位上1的个数
分治,依次使用掩码计算每一位,每两位,每四位……每32位中的1个数,采用类似归并排序的分割方式。
具体思想为
- 先用0…0 1…1相与统计右半的1的个数
- 然后将原数右移一半,相与统计刚刚对应0…0位上的数中1的个数。
- 然后就得到0…0 1…1 0…0 1…1中左半与右半中的1的个数
- 再采用同样的方法将左右的1的个数相加,最后即可得到结果
/*
* 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) {
int mask_1,mask_2,mask_4,mask_8,mask_16;
mask_1=0x55|(0x55<<8);
mask_1=mask_1|(mask_1<<16);//get 0x55555555
mask_2=0x33|(0x33<<8);
mask_2=mask_2|(mask_2<<16);//get 0x33333333
mask_4=0x0f|(0x0f<<8);
mask_4=mask_4|(mask_4<<16);//get 0x0f0f0f0f
mask_8=0xff|(0xff<<16);//get 0x00ff00ff
mask_16=0xff|(0xff<<8);//get 0x0000ffff
x=(x&mask_1)+((x>>1)&mask_1);
x=(x&mask_2)+((x>>2)&mask_2);
x=(x+(x>>4))&mask_4;//x=(x&mask_4)+((x>>4)&mask_4);
x=(x+(x>>8))&mask_8;//x=(x&mask_8)+((x>>8)&mask_8);
x=(x+(x>>16))&mask_16;//x=(x&mask_16)+((x>>16)&mask_16);
return x;
}
bang
实现!操作
!0 = 1,其他都等于0
只有0和0x80000000
的补码与自己相或后是自己本身,而其中只有0最高位为0
于是只要判断一个数与其补码相同且最高位为0时结果为1,其余都为0
/*
* bang - Compute !x without using !
* Examples: bang(3) = 0, bang(0) = 1
* Legal ops: ~ & ^ | + << >>
* Max ops: 12
* Rating: 4
*/
int bang(int x) {
int temp = ~x+1;
return (~((temp|x)>>31))&1;//the highet bit
}
tmin
求最小的二进制补码
最小的二进制补码为0x80000000
/*
* tmin - return minimum two's complement integer
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 4
* Rating: 1
*/
int tmin(void) {
return 0x80<<24;
}
fitBits
判断x是否能被n位的补码表示
即判断x的有效位数
- 先用temp求出原数的位数与n位之间的位数差
- 然后左移消去高位的数
- 算术右移回来,倘若可以表示,则x此时应与原来相等
- 比较原数与此时的x即可,若相等则为1
/*
* fitsBits - return 1 if x can be represented as an
* n-bit, two's complement integer.
* 1 <= n <= 32
* Examples: fitsBits(5,3) = 0, fitsBits(-4,3) = 1
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 15
* Rating: 2
*/
int fitsBits(int x, int n) {
int temp = 32 + (~n) +1;//unused bits
int x1 = ((x<<temp)>>temp);
return !(x^x1);//if equal
}
divpwe2
计算x除以2的n次的结果
将原数右移,右移n位即除以2的n次
由于负数的舍入与正数不同,判断是负数时在第n位加上1从而实现手动舍入
/*
* divpwr2 - Compute x/(2^n), for 0 <= n <= 30
* Round toward zero
* Examples: divpwr2(15,1) = 7, divpwr2(-33,4) = -2
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 15
* Rating: 2
*/
int divpwr2(int x, int n) {
int sign = x>>31;//sign
int temp = sign&((1<<n)+(~0));//if negetive
return (x+temp)>>n;
}
negate
求负数
取补码加一即可
/*
* negate - return -x
* Example: negate(1) = -1.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 5
* Rating: 2
*/
int negate(int x) {
return (~x+1);
}
isPositive
判断是否为正数
当x=0或符号位为1时返回0
/*
* isPositive - return 1 if x > 0, return 0 otherwise
* Example: isPositive(-1) = 0.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 8
* Rating: 3
*/
int isPositive(int x) {
return !((!x)|(x>>31));//if x=0 then !x=1
}
isLessOrEqual
判断x是否小于等于y
相减后得到符号,当xy同号且x<=y时或y为负x为正时x<=y
/*
* isLessOrEqual - if x <= y then return 1, else return 0
* Example: isLessOrEqual(4,5) = 1.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 24
* Rating: 3
*/
int isLessOrEqual(int x, int y) {
int sign = ((y + (~x) +1)>>31)&1;//the sign of y-x
int fx = (x>>31)&1;
int fy = (y>>31)&1;
return ((~(fy^fx)&(!sign)) |//the same signs and y-x>=0
((fy^fx)&fx) );//x<0, y>0 overflow
}
ilog2
求log2 x
即寻找最高位的1的位置,同样采用分治法依次判断左半部分位上有无1
/*
* ilog2 - return floor(log base 2 of x), where x > 0
* Example: ilog2(16) = 4
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 90
* Rating: 4
*/
int ilog2(int x) {
//find the highest 1
int t16, t8, t4, t2, t1, temp;
temp = !!(x>>16);//if 1 exists in the higher 16 bits, temp = 1
t16 = temp<<4;//2^4
x=x>>t16;
temp = !!(x>>8);//if 1 exists in the higher 8 bits, temp = 1
t8 = temp<<3;//2^3
x=x>>t8;
temp = !!(x>>4);//if 1 exists in the higher 4 bits, temp = 1
t4 = temp<<2;//2^2
x=x>>t4;
temp = !!(x>>2);//if 1 exists in the higher 2 bits, temp = 1
t2 = temp<<1;//2^1
x=x>>t2;
temp = !!(x>>1);//if 1 exists in the higher 16 bits, temp = 1
t1 = temp;//2^0
return t16+t8+t4+t2+t1;
}
float_neg
浮点数取反
当uf不为NaN时使用异或取反符号位
/*
* 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) {
int exp = (uf>>23)&0xff;
int frac = uf&((1<<23)-1);
if((exp^0xff)||(!frac)){//exp!=nan or frac!=0
uf = (1<<31)^uf;
}
return uf;
}
float_i2f
将int转换为float的字节表示
根据转换公式和左移小数点的操作即可
- 偏移量:左移小数点的位数加上bias
- 小数部分:小数点移完后的小数部分
- 符号位:不变
/*
* 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) {
int sign,temp,aftershift,shift_times, flag;
sign = x&(1<<31);
if(sign){//abs x
x = -x;
}
if(!(x)){//x=0
return 0;
}
aftershift = x;
shift_times = 0;
while(1){
temp = aftershift;
aftershift = aftershift<<1;
shift_times ++;
if(temp&0x80000000){//1 in the highest bit
break;
}
}
//carry bit
if(((aftershift&0x01ff)>0x0100) ||
((aftershift&0x03ff))==0x0300){
flag = 1;
}
else{
flag = 0;
}
//sign + exp + frac + flag
//E=32-shift_times
return sign+(((159-shift_times)<<23)&0x7f800000)+((aftershift>>9)&0x7fffff)+flag;
}
float_twice
求浮点数乘2的结果的浮点数表示
规格化数exp加一,非规格化数左移一位,NaN不变
/*
* float_twice - 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
*/
unsigned float_twice(unsigned uf) {
if((uf&0x7f800000) == 0){//unnormalized
return ((uf&0x7fffff)<<1)|(uf&0x80000000);
}
if((uf&0x7f800000) != 0x7f800000){
return uf+0x800000;
}
return uf;//NaN
}