其他分享
首页 > 其他分享> > CSAPP_DataLab

CSAPP_DataLab

作者:互联网

Data Lab

//难度4

//实现逻辑非,限制操作:~ & ^ | + << >>

//法一
int logicalNeg(int x) {
  int sign = 1<<31;
  int all1 = ~0;
  return ((((~x)|sign)+1)>>31)+1 & (x^sign)>>31 ; //((x^sign)>>31)
}

/*
思路:
实现逻辑非!,即实现0输出1,非0输出0。
首先要分割0和非0部分,办法是0将保持为0,非0全部转换为负数使其符号位为1。,
用 ~x 翻转,~0 = -1,非0保持不变 ;
(~x) | sign),使-1不变,非0数全部转换为负数且最大值为-2,但注意到x=sign经运算后也为-1,用&(x^sign)>>31剔除,同时,使x=0时,第0位为1
((~x) | sign)+1),使-1变0,负数最大值此时为-1;
((~x) | sign)+1)>>31,0不变,负数全为-1;
((((~x) | sign)+1)>>31)+1,0变1,-1全变为0;
((((~x) | sign)+1)>>31)+1 & (x^sign)>>31,x=0时,(左边1 & 右边-1)输出1;x为非0数时,(左边0 & 右边任何数)输出0;
*/

法二:
int logicalNeg(int x) {
  return ((x|(~x+1))>>31)+1;
}

/*
思路:
利用补码(取反+1)的性质0和Tmin的补码为本身其它数值的补码为其相反数
0与其补码按位或之后,其值为全0,Tmin与其补码、其它数值与其补码,按位或之后,符号位为1;
然后>>31,0不变,Tmin、其它数值为全1即-1;
而后+1,0变为1,Tmin、其它数值为0;
*/

//求一个数最少要用多少位表示

//这道题想了很久,因为允许90个ops,就慢慢找规律,最终想出最高位和次最高位相异时,该数的位数可以确定,
//但实际只能从1位到32位一个个判断,总共操作接近300ops,只能翻起答案来= =,知道会用重复判断的方法,没想到是二分法这么巧妙

int howManyBits(int x) {
  int b16,b8,b4,b2,b1,b0;
  int sign = x>>31;
  x = (sign&~x)|(~sign&x);//x为正数不变;x为负数按位取反,其符号位变为0,可将负数当作正数来求其所需最少的表达位数

// 二分法,不断缩小范围
  b16 = !!(x>>16)<<4;//高十六位是否有1
  x = x>>b16;//如果有(至少需要16位),则将原数右移16位
  b8 = !!(x>>8)<<3;//剩余位高8位是否有1
  x = x>>b8;//如果有(至少需要16+8=24位),则右移8位
  b4 = !!(x>>4)<<2;//剩余位高4位是否有1
  x = x>>b4;//如果有(至少需要16+8+4=28位),则右移4位
  b2 = !!(x>>2)<<1;//剩余位高2位是否有1
  x = x>>b2;//如果有(至少需要16+8+4+2=30位),则右移2位
  b1 = !!(x>>1);//剩余位高1位是否有1
  x = x>>b1;// 如果有(至少需要16+8+4+2+1=31位),则右移位
  b0 = x;//b0为x,数值为1或者0
  return b16+b8+b4+b2+b1+b0+1;//+1表示加上符号位
}

/*
思路:
如果是一个正数,则需要找到它最高为1的是第几位(假设该位是第n位),再加上符号位0(计数为1),那么它最少需要n+1位来表示;
如果是一个负数,则需要找到它最高为0的是第几位(假设该位是第m位),那么它最少需要m位来表示
*/

//float

//一开始是真的懵,想来是浮点数位级表示学得比较模糊

//用无符号整型的位级来表示一个浮点数,同时,对浮点数乘2

  unsigned floatScale2(unsigned uf) {
  int exp = (uf&0x7f800000)>>23;//取指数exp
  int sign = uf&0x80000000;//取符号位sign
  if(exp==0) return uf<<1|sign;//输出(非规化数)*2或者0*2
  if(exp==255) return uf;//输出NaN或者INF(无穷,包括正无穷和负无穷)
  exp++; //计算(规化数)*2,
  if(exp==255) return 0x7f800000|sign;//(规化数)*2后,若指数exp全为1即INF,则输出0x7f800000|sign
  return (exp<<23)|(uf&0x807fffff);//(规化数)*2后,若指数exp不全为1就仍为规划数,则输出(exp<<23)|(uf&0x807fffff)
}

注意:
//第5行,不用exp<<1的原因是:虽然能达到*2的目的,但可能会使exp越出255,突破exp限定的8位

/*

//区分float型的规化数、非规化数、INF、NaN,
//INF、NaN:其E >= 31 计算阶码值2E,超出int型Tmax == 0x7fffffff,直接输出0x80000000
//非规化数:其E < 0 计算阶码值2
E,为小数,直接输出0
//规化数: 其31> E >=0 计算阶码值2E,居于1~230之间,需要左右移
//左右移原理见 CSAPP P82
//其结论是:阶码E大于尾数位数(float型是23位)时,则M左移(23 - E)(最多移8位);
// 阶码E小于尾数位数,则M右移(23 - E)(最多移23位)

//原解法对于E=23时,直接输出tar=0;对于E=31时,将其看作仍可以作M左移运算,事实上2E = 231,已经超过int型Tmax == 0x7fffffff
//但检测可以通过

//笔者做出修正
//对于E=23时,输出tar = sign*M;对于E=31时,直接输出0x80000000(本题Anything out of range return 0x80000000)

/*

未完续待。。。

标签:CSAPP,return,23,int,31,DataLab,sign,exp
来源: https://www.cnblogs.com/duile/p/15259403.html