跳转至

位操作 tricky

位操作 tricks

int

 //以下所有变量默认均为 int 类型
 !!x;  //缩位或 (x 非 0)
 !(~x);  //缩位与 (x 全 1)
    !(x^y);  //x==y
 ~x + 1;  //-x,如果 x 为 0x80000000,返回 0x80000000

 mask = x>>31;
 x = (~x+1) & mask | x & ~mask; //abs(x), mask 用法

 ~(~x & ~y); //x | y



/* 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
     */
int howManyBits(int x)      //Mark
{
    //ref: https://github.com/jerrylzy/CS33/blob/master/Lab/datalab/bits.c
    /*
     * We first bit invert all negative numbers and
     * use binary search to find out the log2(n).
     * Then we add 1 to the final result since we need
     * the MSB to represent the sign.
     * Note: finding the following things are equal:
     * 1. find the most significant bit of 1 for positive numbers
     * 2. find the most significant bit of 0 for negative numbers
     */
    int mask = x>>31;
    x = (x & ~mask) | (~x & mask);

    //the algorithem get the unsigned int bit width(Most Significant One bit to LSb)
    int bit16, bit8, bit4, bit2, bit1, bit0;
    bit16 = (!!(x>>16))<<4;
    x = x >> bit16;

    bit8 = (!!(x>>8))<<3;
    x = x >> bit8;

    bit4 = (!!(x>>4))<<2;
    x = x >> bit4;

    bit2 = (!!(x>>2))<<1;
    x = x >> bit2;

    bit1 = (x>>1)&1;
    x = x >> bit1;

    bit0 = x&1;

    return bit16 + bit8 + bit4 + bit2 + bit1 + bit0 + 1; //plus 1 for 2's complement's sign bit
}

//find the one bit number in x
int count_one_8(unsigned int x){
    /*
     * Firstly, we split the 32 bits to 11 groups, 3 bits per group(except the last group), 
     * Then we can caculate the sum of 3 bits in eache group by  
     * expression: x - (x>>1) -(x>>2) = x2 + x1 + x0 (x=[x2, x1, x0])
     * Then we sum each two contiguous group by a shift-add: tmp + (tmp>>3)
     * The sum(after masked) will be (x0+x1+...x5) + (x6+x7+...x11)*(2^6)^1 + 
     * (x12+x13+...x17)*(2^6)^2+...
     * Last, we can get (x0+x1+...x63)%63 by caculate the sum mod 63.
     */
    unsigned int tmp;
    tmp = x - ((x>>1)&033333333333) - ((x>>2)&011111111111);
    return ((tmp + (tmp>>3))&030707070707)%63;
}

//same way with 4 bits per group
int count_one_16(unsigned int x){
    unsigned int tmp;
    tmp = x - ((x>>1)&0x77777777) - ((x>>2)&0x33333333) - ((x>>3)&0x11111111);
    return ((tmp + (tmp>>4))&0x0f0f0f0f)%255;
}

float

//float
/* 
 * 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
 */
unsigned floatScale2(unsigned uf)
{
    unsigned int m = uf&0x7fffff;
    unsigned int exp = (uf>>23)&0xff;
    unsigned int symbol = uf>>31;
    if(exp==255){
        return uf;
    }else if(exp==0){
        if(m&0x400000){
            exp++;
            m<<=1;
        }else{
            m<<=1;
        }
    }else{
        exp++;
    }
    return (symbol<<31) | (exp<<23) | (m&0x7fffff);
}
/* 
 * 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
 */
int floatFloat2Int(unsigned uf)
{
    int m = uf&0x7fffff;
    int exp = ((uf>>23)&0xff) - 127;
    int symbol = uf>>31;
    int out = 0;

    //[-2^31, 2^31-1]
    if(exp<0){
        return 0;
    }else if(exp<=23){
        out = (0x800000|m)>>(23-exp);
    }else if(exp<=30){
        out = (0x800000|m)<<(exp-23);
    }else{
        return 0x80000000;
    }
    return symbol ? ~out + 1 : out;
}