CSAPP data Lab

CSAPP data Lab

注意,本文代码出于节省括号避免繁杂的考虑,对运算符优先级利用得比较充分,比如 1>>n+1 等价于 1>>(n+1),所以代码里写了1>>n+1。

bitAnd

/* 
 * 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);
}

思路

  • 德摩根定律

getByte

/* 
 * 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) {
    int bias = n<<3;
    return (x>>bias)&0xFF;
}

思路

  • 移位到最低的1byte然后用0xFF提取

logicalShift

/* 
 * logicalShift - shift x to the right by n, using a logical shift
    i
 *   Can assume that 0 <= n <= 31
 *   Examples: logicalShift(0x87654321,4) = 0x08765432
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 20
 *   Rating: 3 
 */
int logicalShift(int x, int n) {
    return (1<<32+~n<<1)+~0 & (x>>n);
  //equal to ((1<<31-n<<1)-1)&(x>>n);
  //负号优先级高于移位
}

思路

  • 因为不能用-,所以用取反加一代替取负

  • 构造低32-nbit的1来提取移位后的数值

  • 因为移位量不能小于0或大于等于32,所以对于n可能是0而导致移位量是32的情况,先移位31位,再移位1位

    小技巧,如果n移位k,k [0, 32],则可以n>>(k-!!k)>>!!k

bitCount

/*
 * 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 mark1 = 0x55;
    int mark2 = 0x33;
    int mark3 = 0x0F;
    mark1 |= mark1<<8;
    mark1 |= mark1<<16;
    mark2 |= mark2<<8;
    mark2 |= mark2<<16;
    mark3 |= mark3<<8;
    mark3 |= mark3<<16;

    x = (x>>1&mark1)+(x&mark1); //every two bits; clear record;
    x = (x>>2&mark2)+(x&mark2); //every four bits; clear record;
    x = (x>>4&mark3)+(x&mark3); //every eight bits; clear record;
    x = (x>>8)+x;   //every 16 bits; record in the low 8 bits;
    x = (x>>16)+x;  //every 32 bits; record in the low 8 bits;
    return x&0xFF;
}

思路

  • 构造0x55555555,提取每两位中的low bit。通过移位及0x55555555,提取每两位中的高位。然后相加,使得结果中,每两位的二进制值就是该两位的bit数目
  • 同样的思路,提取每四位的low bit、high bit,然后相加
  • 因为32==100000(二级制),也就是只需要5位就可以记录有多少bit数,所以不需要每次都构造常数屏蔽高位的值,直接移位相加然后取低8bit就可以得到最终结果

bang

/*
 * bang - Compute !x without using !
 *   Examples: bang(3) = 0, bang(0) = 1
 *   Legal ops: ~ & ^ | + << >>
 *   Max ops: 12
 *   Rating: 4 
 */
int bang(int x) {
    x |= x>>1;
    x |= x>>2;
    x |= x>>4;
    x |= x>>8;
    x |= x>>16;
    return ~x&0x1;
}

思路

  • 如果非0,位模式从最高位的1到最低位都填充为1,
  • 如果为0,则位模式还是保持全0

tmin

/* 
 * tmin - return minimum two's complement integer 
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 4
 *   Rating: 1
 */
int tmin(void) {
    return 1<<31;
}

fitBits

/* 
 * 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) {
    return !(x>>n+~0)|!((x>>n+~0)+1);
  //equal to !(x>>n-1) | !((x>>n-1)+1)
}

思路

  • 算术移n-1位,如果是负数,且可以用n bits的补码表示,则得到-1。如果是正数,则得到0。

divpwr2

/* 
 * 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 t = x>>31;
    return (x+(t&1<1)+1))>>n;
  //equal to (x+(t&1<>n;
  //note that & 的优先级低于<<
}

思路

  • 直接移位是round down,无论是负数还是正数
  • 所以要实现round to zero , C表达式为x<0 ? x+(pow(2,n)-1)>>n : x>>n

negate

/* 
 * negate - return -x 
 *   Example: negate(1) = -1.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 5
 *   Rating: 2
 */
int negate(int x) {
    return ~x+1;
}

思路

  • 直接取反再加1

isPositive

/* 
 * 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>>31)&!!x;
}

思路

  • 符号位判断,并且非0

isLessOrEqual

/* 
 * 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) {
    return !!(x>>31&~(y>>31)) | !(~(x>>31)&(y>>31))&(x+~y+1>>31) | !(x^y);
    //equal to  !!(x>>31&~(y>>31)) | !(~(x>>31)&(y>>31))&(x-y>>31) | !(x^y)
}

思路

  • x<0&&y>0 | !(x>0&&y<0)&&(x-y>0) | x==y

ilog2

/*
 * 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) {
    int mark1 = 0x55;
    int mark2 = 0x33;
    int mark3 = 0x0F;
    mark1 |= mark1<<8;
    mark1 |= mark1<<16;
    mark2 |= mark2<<8;
    mark2 |= mark2<<16;
    mark3 |= mark3<<8;
    mark3 |= mark3<<16;

    x |= x>>1;
    x |= x>>2;
    x |= x>>4;
    x |= x>>8;
    x |= x>>16;
    x >>= 1;

    x = (x>>1&mark1)+(x&mark1); //every two bits; clear record;
    x = (x>>2&mark2)+(x&mark2); //every four bits; clear record;
    x = (x>>4&mark3)+(x&mark3); //every eight bits; clear record;
    x = (x>>8)+x;   //every 16 bits; record in the low 8 bits;
    x = (x>>16)+x;  //every 32 bits; record in the low 8 bits;
    return x&0xFF;
}

思路

  • 先构造从最高的1到最低位均为1的二进制,然后类似bitCount

float_neg

/* 
 * 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) {
    unsigned t = uf&0x7FFFFFFF;
    if(t^0x7F800000 && (t>>23)+1>>8)
        return uf;
    else 
        return uf^0x80000000;
}

思路

  • 判别是否是NaN。先判断尾数是否全0,然后用(t>>23)+1>>8判断exp是否全1

float_i2f

/* 
 * 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) {
    unsigned shiftLeft=0;
    unsigned afterShift, tmp, flag;
    unsigned absX=x;
    unsigned sign=0;
    //special case
    if (x==0) return 0;
    //if x < 0, sign = 1000...,abs_x = -x
    if (x<0)
    {
        sign=0x80000000;
        absX=-x;
    }
    afterShift=absX;
    //count shift_left and after_shift
    while (1)
    {
        tmp=afterShift;
        afterShift<<=1;
        shiftLeft++;
        if (tmp & 0x80000000) break;
    }
    if ((afterShift & 0x01ff)>0x0100)
        flag=1;
    else if ((afterShift & 0x03ff)==0x0300)
        flag=1;
    else
        flag=0;

    return sign + (afterShift>>9) + ((159-shiftLeft)<<23) + flag;
}
//from http://www.cnblogs.com/tenlee/p/4951639.html

思路

  • 分情况处理0、负数、正数

  • 要处理舍人

    • 向接近的舍入
    • 如果处于中间,向偶数舍入
  • 舍入时,如果尾数加一,exp有可能需要进位,这时候直接加一效果一样,可以导致exp进位,不需要特殊处理。如果exp等于0xFE,那么进位就变成了inf,也是合法的

float_twict

/* 
 * 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) {
    unsigned t = uf&0x7FFFFFFF;
    unsigned temp = t&0x7F800000;
    unsigned temp2 = uf&0xFF800000;
    int expFull = !(temp^0x7F800000);
    if(t^0x7F800000 && expFull)
        return uf;
    if(expFull){
        return temp2;
    }
    if(!(t&0x7F800000)){
        unsigned k = (uf&0x7FFFFF);
        return temp2+(k<<1);
    }
    return (temp>>23)+1<<23 | uf&0x807FFFFF;
}

思路

  • 分情况处理三种IEEE754的情况
  • 需要注意exp全0时,乘以二就是尾数乘以二,如果发生进位需要exp进位,不需要特殊处理(第三个if),因为进位直接导致exp加一,这就足够了

你可能感兴趣的:(CSAPP)