ICS datalab

发布于 2019-09-11  1606 次阅读


rating 1

int bitAnd(int x, int y) {
         return ~((~x)|(~y));
}

~(A&B)=(~A)|(~B).

int evenBits(void) {
    int x = 0x55, y = (x << 8) | x;
    return (y << 16) | y;
}

0x55=01010101,将x复制4倍合在一起.

int fitsShort(int x) {
    int y = (x << 16) >> 16;
    return !(x ^ y);
}

x 左移16位再右移16位,相当于把x转为16进制数.

int isTmax(int x) {
    int y = ~x;
    return (!(y + y)) & (!(!y));
}

x为最大值=>(~x)+(~x)=0

特殊情况:x=-1 => ~x=0

int minusOne(void) {
    return ~0;
}

~0=-1.

int upperBits(int n) {
    int mi = ~0;
    return ((!n) + mi) & ((~(2 << (n + mi))) << (33 + (~n)));
}

0<n<32: (~(1 << n)) << (32 - n), 1左移n位取反得到前n位为1的数,左移32-n位得到答案;

n=0: !n + ~0 = 0,故答案为0;

n=32: 将 1 << n 变为 2 << (n - 1) 防止错误.

rating 2

int allEvenBits(int x) {
    int a = 0x55;
    int b = (a << 8) | a;
    int c = (b << 16) | b;
    return !((x & c) ^ c);
}

和evenbits类似,制造一个偶数位均为1的数与其取并后看是否相等.

int byteSwap(int x, int n, int m) {
    int n4 = n << 3, m4 = m << 3;
    int nb = (x >> n4) & 0xFF;
    int mb = (x >> m4) & 0xFF;
    int rest = x ^ (nb << n4) ^ (mb << m4);
    return (nb << m4) | (mb << n4) | rest;
}

先把第n字节和第m字节取下来,再获得把原数第n字节和第m字节抹掉的数,再把它们反向取或。

int copyLSB(int x) {
    return x << 31 >> 31;
}

只留下符号位。

int divpwr2(int x, int n) {
    return (x + (((1 << n) + (~0)) & (x >> 31))) >> n;
}

难点在于向0取整,当x为负数时将x加上(1<<n)-1,这样能保证向上取整。

int leastBitPos(int x) {
    return ((~x) + 1) & x;
}

即lowbit,检验可知。

int oddBits(void) {
    int x = 0xAA << 8 | 0xAA;
    return x << 16 | x;
}

与evenbits类似。

rating 3

int bitMask(int highbit, int lowbit) {
    int t = (2 << highbit) + (~(1 << lowbit)) + 1;
    int x = highbit + (~lowbit) + 1;
    return (~(x >> 31)) & t;
}

答案=(1<<(highbit +1)) - (1<< lowbit)

若highbit - lowbit < 0 则输出0,用一个&额外判断.

int isLess(int x, int y) {
    int x0 = (x >> 31), y0 = (y >> 31);
    int rest = ((x + (~y) + 1) >> 31) & 1;
    int o = x0 ^ y0;
    return (o & (y0 + 1)) + (~o & rest);
}

难点在于不能直接做减法(负数减正数=正数),要额外判断一下x,y的符号

y0 + 1为x,y异号的答案,x,y同号时直接相减判断符号即可.

int logicalShift(int x, int n) {
    return (x >> n) + (((x >> 31) & !!n) << (33 + (~n)));
}

x为负数时右移补0,把补的1加上1<<(32-n)全部进位即可.

int satMul2(int x) {
    int x0 = x >> 31;
    int mulx = x << 1;
    int x1 = mulx >> 31;
    int x2 = x0 ^ x1, x3 = ~x2;
    int Tmin = 1 << 31, Tmax = Tmin + ~0;
    return (x3 & mulx) + (x2 & x0 & Tmin) + (x2 & x1 & Tmax);
}

分类讨论x和x<<1的符号,每种情况若满足条件则返回对应值,否则返回0,然后把所有情况相加。

int subOK(int x, int y) {
    int x0 = x >> 31, y0 = y >> 31;
    int z0 = (x + (~y) + 1) >> 31;
    return !((x0 ^ y0) & (!(y0 ^ z0)));
}

判断x,y符号同x-y符号,x,y同号=》可以减,x,y异号=》判断y与x-y是否异号...

rating 4

int bang(int x) {
    int a = x | (x >> 16);
    int b = (a | (a >> 8)) & 0xFF;
    return (((~b) + 1) >> 31) + 1;
}

判断x是否某一位为1:将后16位与前16位取或,前8位与后8位取或,...,则可知道是否含1.

上述函数使用了一种优化:或到前8位后直接判断符号(0或正数)

int bitParity(int x) {
    int a = x ^ (x >> 16);
    int b = a ^ (a >> 8);
    int c = b ^ (b >> 4);
    int d = c ^ (c >> 2);
    return (d ^ (d >> 1)) & 1;
}

与上题类似,后16位与前16位取异或,...,只需确认第1位的奇偶性即可。

int isPower2(int x) {
    return !(((x & ((~x) + 1)) ^ x) | (x >> 31) | !x);
}

用lowbit得到x为1最低位的数,直接判断x是否等于它,注意x为负数/0特判.

unsigned float_i2f(int x) {
    int bias = 127;
    int t = 0;
    int s, y, t0, exp, M, bs, qs, qM, o = 0;
    if(x == (1 << 31))
    {
        s = 1;
        exp = 31 + bias;
        return (s << 31) | (exp << 23);
    }
    if(x < 0) x = -x, s = 1;else s = 0;
    if(!x) return 0;
    y = x;
    while(y) t += 1, y >>= 1;
    t0 = t - 1;
    exp = t0 + bias;
    if(t0 <= 23) M = (x - (1 << t0)) << (23 - t0);
    else
    {
        bs = 1 << (t0 - 24);
        qs = (bs << 1) - 1;
        qM = x & qs;
        M = (x - (1 << t0)) >> (t0 - 23);
        if(qM != bs) o = qM > bs;
        else o = M & 1;
    }
    return ((s << 31) | (exp << 23) | M) + o;
}

如果x是负数先转正数;再分步提取exp、M.

int leftBitCount(int x) {
    int pos = ~0;
    pos = pos + (((x + (1 << (pos + 16))) >> 31) & 16);
    pos = pos + (((x + (1 << (pos + 8))) >> 31) & 8);
    pos = pos + (((x + (1 << (pos + 4))) >> 31) & 4);
    pos = pos + (((x + (1 << (pos + 2))) >> 31) & 2);
    pos = pos + (((x + (1 << (pos + 1))) >> 31) & 1);
    return (x >> 31) & (32 + ~pos);
}

倍增,初始pos为0,判断pos+16,pos+8,...,pos+1之后的位是否均为1,是就加上16,8,...,1,否则不加。


WRYYYYYYYYY!