csapp datalab

计算机中的数以二进制的形式存储和运算,每个比特不是0就是1。计算机通过对比特进行不同方式的编码和描述,从而执行纷繁复杂的各种任务。我们有诸多基于底层的接口,所以一般不会直接接触到比特的运算。datalab直接与编码数字序列的0和1打交道,通过对整数和浮点数的位操作来实现一系列的操作。

整数运算

bitXor

x^y using only ~ and &
Example: bitXor(4, 5) = 1
Legal ops: ~ &
Max ops: 14
Rating: 1

假设a,b均为由单个二进制位表示的数
则a,b,a^b对应真值表如下
a^b在a,b中只有一个取1时取1

a b a^b
0 1 1
1 1 0
1 0 1
0 0 1

(a&b)|(b&a)
a取0,b取1时为1,
b取0,a取1时为1,
((a&b)|(~b&a))即为结果
但是只能用和&,化简得(((a)&b))&(((~b)&a))

int bitXor(int x, int y) {
  return (~((~x)&y))&(~((~y)&x));
}

tmin

return minimum two’s complement integer
Legal ops: ! ~ & ^ | + << >>
Max ops: 4
Rating: 1

32位时补码可以表示最大整数为1>>31

int tmin(void) {
 return 1>>31;
}

isTmax

returns 1 if x is the maximum, two’s complement number,and 0 otherwise
Legal ops: ! ~ & ^ | +
Max ops: 10
Rating: 1

2(Tmax+1)会溢出为0,符合2*num等于0的数只有0x0和0x10000000
再排除0即可
!(x+1+x+1)&!(x+1)
调试时报错,不可以使用0xff和0x0以外的常数,由0xff和0x0变换得到0x1
0xff+0xff=0x1fe
0x1fe&0xff=0xfe
0xfe^0xff=0x1

//以下的tmp即为0x1;
 int isTmax(int x) {
   tmp=((0xff+0xff)&0xff)^0xff;
  return !(x+tmp+x+tmp)&!(x+tmp);
}

allOddBits

return 1 if all odd-numbered bits in word set to 1
where bits are numbered from 0 (least significant) to 31 (most significant)
Examples allOddBits(0xFFFFFFFD) = 0, allOddBits(0xAAAAAAAA) = 1
Legal ops: ! ~ & ^ | + << >>
Max ops: 12
Rating: 2

奇数位全为0,偶数位全为1的32位二进制数的十六进制表示为0xaaaaaaaa
若x满足奇数位全为1,则取反后奇数位全为0
则x&0xaaaaaaaa所有位均为0

int allOddBits(int x) {
  return !(~x&0xaaaaaaaa);
}

negate

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

一个数的相反数的补码表示为该数的反码再加一

x+~x=0xffffffff=-1
x+~x+1=0
int negate(int x) {
  return (~x+1);
}

isAsciiDigit

return 1 if 0x30 <= x <= 0x39 (ASCII codes for characters ‘0’ to ‘9’)
Example: isAsciiDigit(0x35) = 1.
isAsciiDigit(0x3a) = 0.
isAsciiDigit(0x05) = 0.
Legal ops: ! ~ & ^ | + << >>
Max ops: 15
Rating: 3

判断x在0x30到0x39
x-0x30的符号位为0
x-0x3a的符号位为1

int isAsciiDigit(int x) {
  return (!((x+(~(0x30)+1))>>31))&((x+(~(0x3A)+1))>>31);
}

conditional

same as x ? y : z
Example: conditional(2,4,5) = 4
Legal ops: ! ~ & ^ | + << >>
Max ops: 16
Rating: 3

0xffffffff&a=a,0x00000000&b=0x00000000
当x=1时,得到0xffffffff(0),当x=0时,得到0x00000000(1)
思路一:!x-1 也即!x+~1+1

int conditional(int x, int y, int z) {
  cond=!x+~1+1
  return (mask&y)|((~mask&z);
}
int conditional(int x, int y, int z) {
  return ((!x+~1+1)&y)|((~!x+1)&z);
}

思路二:位移

int conditional(int x, int y, int z) {
  mask=(x>>31)<<31;
  return (mask&y)|(~mask&z);
}

isLessOrEqual

if x <= y then return 1, else return 0
Example: isLessOrEqual(4,5) = 1.
Legal ops: ! ~ & ^ | + << >>
Max ops: 24
Rating: 3

  1. 在x与y同号的情况下转换为p=y-x>=0,然后p符号位(p>>31)&1为0则返回1,符号位1则返回0;
  2. 异号时,只要x>=0,就要返回0,否则返回1,由(x>>31)&1判断;
  3. c=a+b可作为x,y同号还是异号的判断。
int isLessOrEqual(int x, int y) {
  int a=x>>31;
  int b=y>>31;
  int c=a^b;
  int p=y+(~x+1);
  int q=!((p>>31)&1);
  int ans=(c&q)|(!c&a);
  return ans;
}

logicalNeg

implement the ! operator, using all of the legal operators except !
Examples: logicalNeg(3) = 0, logicalNeg(0) = 1
Legal ops: ~ & ^ | + << >>
Max ops: 12
Rating: 4

令y=~x+1,考虑x与y的符号位:

  1. 当x=0x0时,x,y两者符号位都为0;
  2. 当x=0x8000 0000时,x,y两者符号位都为1;
  3. 否则,两者符号位为01或10;
  4. 根据离散数学的真值表得出(x)&(y),则当且仅当x=0x0时,其符号位为1
int logicalNeg(int x) {
  return ((~(~x+1)&~x)>>31)&1;
}

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) {
	int temp=x^(x>>31);//x小于0时取反码
    int isZero=!temp;
    //notZeroMask is 0xffffffff
    int notZeroMask=(!(!temp)<<31)>>31;
    int bit_16,bit_8,bit_4,bit_2,bit_1;
    bit_16=!(!(temp>>16))<<4;
    //see if the high 16bits have value,if have,then we need at least 16 bits
    //if the highest 16 bits have value,then rightshift 16 to see the exact place of  
    //if not means they are all zero,right shift nothing and we should only consider the low 16 bits
    temp=temp>>bit_16;
    bit_8=!(!(temp>>8))<<3;
    temp=temp>>bit_8;
    bit_4=!(!(temp>>4))<<2;
    temp=temp>>bit_4;
    bit_2=!(!(temp>>2))<<1;
    temp=temp>>bit_2;
    bit_1=!(!(temp>>1));
    temp=bit_16+bit_8+bit_4+bit_2+bit_1+2;//at least we need one bit for 1 to tmax,
    //and we need another bit for sign
    return isZero|(temp&notZeroMask);
}

浮点数运算

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 s = uf&0x80000000;
	unsigned exp = uf&0x7f800000;
	unsigned frac = uf&0x007fffff;
	if(!exp) {
		frac<<=1;
	}else if(exp^0x7f800000) {
		exp += 0x00800000;
		if(!(exp^0x7f800000)) {
			frac = 0;
		}
	}
	return s|exp|frac;
}

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 sign=(uf>>31)&1;//取得符号位
  int exp=uf>>23&0xff;//取得阶码
  int frac=uf&0x7fffffff;//取得小数位
  int E=exp-127;//计算E
  if(exp==255||E>30){
    return 0x80000000u;//如果超出表示范围,返回0x80000000u
  }
  else if(!exp||E<0) {
    return 0;//如果exp为0或偏移量小于0,均为不大于1的小数,E均等于1,则舍入到0
  }
  frac=frac|(1<<23);//frac=frac+1.0
  //小数点在23位处,根据E与23的相对位置调整小数点
  if (E>23){
    frac=frac<<(E-23);
  } else {
    frac=frac>>(23-E);
  }
  if (sign) {
    frac = ~(frac) + 1;
  }
  return frac;
}

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-levelrepresentation of a single-precision floating point values.
Legal ops: Any integer/unsigned operationsincl. ||, &&. also if, while
Max ops: 30
Rating: 4

unsigned float_i2f_2(int x) {  
    int sign = x>>31&1; 
    int i;  
    int exponent;   
    int fraction; 
    int delta;  
    int fraction_mask;  
    if(x == 0)  
        return x;  
    else if(x==0x80000000)  
        exponent=158; //x为Tmin(-2^31)时,exponent=31+127=158 
    else{  
        if (sign)  
            x = -x;  
        i = 30;  
        while ( !(x >> i) )  
            i--;//小数点偏移位数  
        exponent = i + 127;
        x = x << (31 - i);  
        fraction_mask = 0x7fffff;  
        fraction = fraction_mask & (x >> 8);//32位数字舍弃低八位和首位的1得到23位的小数域
		
        x = x & 0xff; //舍入部分 
        delta = x > 128 || ((x == 128) && (fraction & 1));//向偶数舍入
		
        fraction += delta;  
        if(fraction >> 23) {  
            fraction &= fraction_mask;//处理溢出情况  
            exponent += 1;  
        }  
    }  
    return (sign<<31)|(exponent<<23)|fraction;  
}  

bitCount

returns count of number of 1’s in word
Examples: bitCount(5) = 2, bitCount(7) = 3
Legal ops: ! ~ & ^ | + << >>
Max ops: 40
Rating: 4

分而治之,首先我们考虑两位的情况
例如二进制10,10&01表明最低位是否为1,(x>>1)&1,表明最低位的零位是否为1,
(x&0x1)+(x>>1)&0x1
计算每一位中1的个数并且相加

int bitcount2(int x)
{
    int bit1=0x1;
    return x&bit1+(x>>1)&bit1;
}

接下来我们考虑四位的情况
例如1001,1001&0101=0001,(1001>>1)&0101=0001;
0001+0100=0101表示每两位均各有1个1,
将四位看作两段两位的二进制数,每段的1的个数由一个二位二进制数表示
0101&0011=0001;(0101>>2)=0001,0001&0011=0001;
计算每两位中1的个数并且相加
0001+0001=0010,即为最后的答案

int bitcount4(int x)
{
    int mask1=0x1;
    int mask2=0x3;
    int ans=(x&mask1)+(x>>1)&mask1;
    ans=(ans&mask2)+(ans>>2)&mask2;
    return ans;
}

接下来我们考虑八位的情况
例如01111001,01111001&01010101=01010001,01111001>>1=00111100;
00101100&01010101=00010100,00010100+01010001=01100101;
每二位分别有1,2,1,1个1
接下来计算每四位中1的个数
01100101&00110011=00100001,01100101>>2=00011001;
00100001+00010001=00110010
每四位分别有3,2个1
接下来计算每8位中1的个数

int bitcount8(int x)
{
    int mask1=0x55;
    int mask2=0x33;
    int mask3=0x0f;
    int ans=(x&mask1)+((x>>1)&mask1);
    ans=(ans&mask2)+((ans>>2)&mask2);
    ans=(ans&mask3)+((ans>>4)&mask3);
}

推广得到32位的计算如下

int bitCount(int x) {
  int _mask1 = (0x55)|(0x55<<8);
  int _mask2 = (0x33)|(0x33<<8);
  int _mask3 = (0x0f)|(0x0f<<8);
  int mask1 = _mask1|(_mask1<<16);
  int mask2 = _mask2|(_mask2<<16);
  int mask3 = _mask3|(_mask3<<16);
  int mask4 = (0xff)|(0xff<<16);
  int mask5 = (0xff)|(0xff<<8);

  int ans = (x & mask1) + ((x>>1) & mask1);
  ans = (ans & mask2) + ((ans>>2) & mask2);
  ans = (ans & mask3) + ((ans>>4) & mask3);
  ans = (ans & mask4) + ((ans>>8) & mask4);
  ans = (ans & mask5) + ((ans>>16) & mask5);

  return ans;
}

你可能感兴趣的:(csapp datalab)