实验一

/* 
 * bitAnd - x&y using only ~ and | 
 *   Example: bitAnd(6, 5) = 4
 *   Legal ops: ~ |
 *   Max ops: 8
 *   Rating: 1
 */
int bitAnd(int x, int y) {
  
  //~(a&b) = ~a | ~b;
  //a&b = ~(~a | ~b);
  return ~((~x) | (~y));
}

根据德摩根律~(x&y) = (~x | ~y)

/* 
 * 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 - 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 mask = ~(((1<<31)>>n)<<1);
  return mask & x>>n;
}

只进行x>>n,如例子,会得到0xf8765432, 所以要用0x0fffffff, 这个值不容易直接得到,但是可以通过0x1000000取反得到。

/*
 * 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 mask1 = 0x55555555;
    int mask2 = 0x33333333;
    int mask3 = 0x0f0f0f0f;
    int mask4 = 0x00ff00ff;
    int mask5 = 0x0000ffff;
    x = (x&mask1)+((x>>1)&mask1);
    x = (x&mask2)+((x>>2)&mask2);
    x = (x&mask3)+((x>>4)&mask3); 
    x = (x&mask4)+((x>>8)&mask4); 
    x = (x&mask5)+((x>>16)&mask5);  
  return x;
}

算法来自于http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel

依照http://stackoverflow.com/questions/3815165/how-to-implement-bitcount-using-only-bitwise-operators中的解释是使用了分而治之的方法

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

在补码表示中,只有0可以做到原码和补码的符号位一样,其它任何数的补码和原码的符号位都是相反的。

应当注意!和~的区别。

/* 
 * 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 r, c;
    c = 33 + ~n;
    r = !(((x << c)>>c)^x);
    return r;
}

判断x的范围是否在-2^(n-1)  ~2^(n-1)-1之间,如果在,则x不会因为左右移动(32-n)发生溢出而改变。

/* 
 * 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) {  
    //all zeros or all ones  
    int signx=x>>31;  
    //int mask=(1<<n)+(-1);  
    int mask=(1<<n)+(~0);  
    int bias=signx&mask;  
    return (x+bias)>>n; 
}

可以见中文CSAPP里的P65有推导过程。我们需要除法向零舍入,但是在负数情况下右移操作会让除法向负无穷舍入,所以需要加上一个bias。

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

根据符号位不同,>>31后可以得到32个1或者32个0。

/* 
 * 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 signx=x>>31;  
  int signy=y>>31;  
  int signSame=((x+(~y))>>31)&(!(signx^signy));  
  int signDiffer=signx&(!signy);  
  return signDiffer|signSame;  
}  

当符号相同时, x+(~y) = x-y-1, 如果x-y>0, 那么 x-y-1 >= 0,即符号位为0;  如果x-y<=0, 那么x-y-1<0, 即符号位为1;

当符号不相同时,若x>0且y<0,那么也符合条件

/*
 * 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) {
  //binary search +16 +8 +4 +2 +1
  int bCnt = (!!(x>>16))<<4;
  bCnt = bCnt +((!!(x>>(bCnt+8)))<<3);
  bCnt = bCnt +((!!(x>>(bCnt+4)))<<2);
  bCnt = bCnt +(!!(x>>(bCnt+2))<<1);
  bCnt = bCnt +(!!(x>>(bCnt+1)));
  return bCnt;
}

以第一步为例,x>>16并且两次逻辑非,那么若x>>16大于零则得到1,说明对应log(x) >= 4,于是1<<4

/* 
 * 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 result;  
  unsigned tmp;  
  tmp=uf&(0x7fffffff);  
  result=uf^0x80000000;  
  if(tmp>0x7f800000)  
        result=uf;  
 return result;  
}   

0x7fffffff取取除了符号位剩下的位;

对0x80000000异或可以让符号位取反;

if语句中判断0x7f800000,代表着浮点数中的exp字段全为1,即NaN的判断(exp字段全为1,frac字段不为0),当uf is NaN时返回uf,否则返回-f。

/*    return 1 if x contain even 1s, 0 otherwise;
       assume x = 32w */
int even_ones(unsigned x)
{
    int temp = x >> 16 ^ x;
    temp = temp >> 8 ^ temp;
    temp = temp >> 4 ^ temp;
    temp = temp >> 2 ^ temp;
    temp = temp >> 1 ^ temp;
    return !(temp & 1);
}

每次将伪码对半比较,判断其中1的个数

以1100 0110为例,第一次对半比较 1100^0110 = 1010,第二次对半比较 10^10 = 00, 第三次对半比较 0^0=0, 也就是说最后一次比较后得到的数的最后一位为0,则最初的数中含偶数个1,否则含奇数个1;为了取得这个数,我们使用 &1单独拿出,并取!符合题目条件。

/* 
 * 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 i)
{
    if(i == 0) return 0;
    unsigned x = i>0?i:-i;
    int sign = i>0?0:1;
    int w = sizeof(int)<<3;
    int j;
    for(j=w-1; j>=0; j--){ //ÕÒµ½×î¸ßλ
        if( (x>>j) & 1) break;
    }
    unsigned bias = 127;
    unsigned exp, frac;
    exp = bias + j;
    if(j <= 23) frac = x<<(23-j);
    else {
        frac = x>>(j-23);
        unsigned mask = (1<<(j-23)) - 1;
        if( (x&mask) > (1<<(j-24)) ) frac++; //ÐèÒªÉáÈëµ½´óÖµ
        else if( (x&mask) == 1<<(j-24)  &&  (frac&1)) frac++; //ÉáÈ뵽żÊý
        if(frac == (1<<24)) exp++; //ÉáÈ뵽żÊý³¬¹ý(1<<24) - 1£¬Ö¸ÊýÐèÒªÔÙ¼Ó1
    }
    return sign<<31 | exp<<23 | frac&0x7FFFFF;
}

参考中文书P74一个将12345转为12345.0的实例

/* 
 * 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(float_bits f){
    unsigned sign = f>>31;
    unsigned exp = (f>>23) & 0xFF;
    unsigned frac = f&0x7FFFFF;
    if(exp == 0) return sign<<31 | frac<<1;
    else if(exp < 254) return sign<<31 | (exp+1)<<23 | frac;
    else if(exp == 254) return sign<<31 | 0xFF<<23;
    else return f;
}

了解规范化与非规范化的差别

原文地址:https://www.cnblogs.com/autoria/p/5572738.html