天天看点

CSAPP lab1 datalab-handout

这是一个关于机器级的整数、浮点数表示和位运算的实验。要求用给定的操作符、尽可能少的操作数去实现对应的函数功能。

完整的实验包:链接: https://pan.baidu.com/s/1xUBi3XDlidPQFNexbjXoLw 密码: 2333

以下是全部函数的代码:

1 /*****************************计算log2(x)向下取整*******************************/
  2 int ilog2(int x) {
  3     int bit_16, bit_8, bit_4, bit_2, bit_1;
  4     bit_16 = (!!(x >> 16)) << 4;                //如果x >> 16非零,则至少有16位
  5     x = x >> bit_16;
  6     bit_8 = (!!(x >> 8)) << 3;
  7     x = x >> bit_8;
  8     bit_4 = (!!(x >> 4)) << 2;
  9     x = x >> bit_4;
 10     bit_2 = (!!(x >> 2)) << 1;
 11     x = x >> bit_2;
 12     bit_1 = x >> 1;      //还剩两位时,直接判断首位。bit_1 == 1,剩两位;bit_1 == 0,剩一位
 13     return bit_16 + bit_8 + bit_4 + bit_2 + bit_1;
     //实际是(bit_1 + 1)-1;由于向下舍入,总位数减一
 14 }
 15 
 16 /****************************表达x所需要的最少位数******************************/
 17 int howManyBits(int x) {
 18     int bit_16, bit_8, bit_4, bit_2, bit_1, result;
 19     int k = x >> 31;
 20     int temp = x ^ k;                      
     //x为正,temp = x;x为负,temp = ~x
 21     int isZero = (!!(temp << 31)) >> 31; 
     //x = 0或x = -1时,temp = 0,isZero = 0...0;否则isZero = 1...1
 22     bit_16 = (!!(temp >> 16)) << 4;
 23     temp = temp >> bit_16;
 24     bit_8 = (!!(temp << 8)) << 3;
 25     temp = temp >> bit_8;
 26     bit_4 = (!!(temp << 4)) << 2;
 27     temp = temp >> bit_4;
 28     bit_2 = (!!(temp << 2)) << 1;
 29     temp = temp >> bit_2;
 30     bit_1 = temp >> 1;
 31     result = bit_16 + bit_8 + bit_4 + bit_2 + bit_1 + 2;
      //真正位数为bit_16 + ... + bit_1 + 1,再加符号位一位
 32     return (!isZero) | (result & isZero);
 33 }
 34 
 35 /************************************逻辑右移*************************************/
 36 int logicshift(int x, int n)
 37 {
 38     int temp = ~(1 << 31);
 39     temp = ((temp >> n) << 1) + 1;                //生成掩码0...01...1(前面为n个0)
 40     return (x >> n) & temp;
 41 }
 42 
 43 /*************************类似于c语言中的x ? y : z**********************************/
 44 int conditional(int x, int y,int z)
 45 {
 46     int temp = (~(!x)) + 1;                      //要在return中完成,必须生成x,y的掩码
 47     return (temp & z) | ((~temp) & y);           //当x = 0时,temp = 1...1;当x != 0时,temp = 0...0
 48 }
 49 
 50 /*********************************** x/ 2^n *****************************************/
 51 int divpwr2(int x, int n)
 52 {
 53     int temp = (1 << n) + (~0);                  //temp为baising(偏置),1...1(共n个1)
 54     return (x + ((x >> 31) & temp)) >> n;        //只有负数才要加偏置,所以temp要与符号位相与
 55 }
 56 
 57 /****************************** x < y ? ***********************************/
 58 int isLessOrEqual(int x, int y)
 59 {
 60     int signx = x >> 31;
 61     int signy = y >> 31;
 62     int signEqual = (!(signx ^ signy) & ((x + (~y)) >> 31));//符号位不同时,做差
 63     int signDiffer = signx & (!signy);                      //符号位相同,直接比较符号位
 64     return signEqual | signDiffer;
 65 }
 66 
 67 /**********************操作数更小的版本**************************/
 68 int isLessOrEqual_2(int x, int y)
 69 {
 70     int not_y = ~y;
 71     return ((((x + not_y) & (x ^ not_y)) | (x & not_y)) >> 31) & 1;
 72     //        x-y-1<0 <----------x,y不同号------>x为负,y为正,才为正
 73 }
 74
 75 /****************************不用负号得到-x*********************************/
 76 int negate(int x)
 77 {
 78     return ~x + 1;                //按位取反,末位加一
 79 }
 80 
 81 /**********************返回最小的补码***************************************/
 82 int tmin(void)
 83 {
 84     return 1 << 31;
 85 }
 86 
 87 /*************************只用~ 和 | 实现x&y*****************************/
 88 int bitAnd(int x, int y)
 89 {
 90     return ~(~x | y);            //摩根律
 91 }
 92 
 93 /**************************从字x中取出第n个字节*********************************/
 94 int getByte(int x, int n)
 95 {
 96     return (x >> (n << 3)) & 0xff;        //是从0开始数的
 97 }
 98 
 99 /*********************************计算x中1的数目*********************************/
100 int bitCount(int x)
101 {
102     int result;
103     int tmpmark1 = 0x55 + (0x55 << 8);                //最大0xff
104     int mark1 = tmpmark1 + (tmpmark1 << 16);
105     int tmpmark2 = 0x33 + (0x33 <<8);
106     int mark2 = tmpmark2 + (tmpmark2 << 16);
107     int tmpmark3 = 0x0f + (0x0f << 8);
108     int mark3 = tmpmark3 + (tmpmark3 << 16);
109     int mark4 = 0xff + (0xff << 16);
110     int mark5 = 0xff + (0xff << 8);                  //以上生成5个掩码
111 
112     result = (x & mark1) + ((x >> 1) & mark1);
113     result = (result & mark2) + ((result >> 2) & mark2);   //这两个由于进位问题,不能先加再与
114     result = (result + (result >> 4)) & mark3;              //分治
115     result = (result + (result >> 8)) & mark4;
116     result = (result + (result >> 16)) & mark5;
117     return result;
118 }
119 
120 /***************************计算uf/2*********************************/
121 unsigned float_half(unsigned uf)
122 {
123     unsigned s = uf & 0x80000000;            
124     unsigned exp = uf & 0x7f800000;
125     int lsb = ((uf & 3) == 3);                //判断frac最后两位是否为11
126     if (exp == 0x7f800000)
127         return uf;
128     else if (exp <= 0x800000)
129         return s | (((uf ^ s) + lsb) >> 1);  //uf^s将符号位置零,uf^s = frac + exp末位
130     else
131         return uf - 0x800000;                 //整体思路就是模拟
132 }
133 
134 /****************************计算(float)x***********************************/
135 int float_f2i(unsigned uf)
136 {
137     int abs;
138     int sign = uf >> 31;
139     int exp = (uf >> 23) & 0xff;
140     int frac = uf & 0x007fffff;
141     if (exp < 0x7f)        return 0;
142     if (exp > 157)        return 0x80000000;                //Tmax = 2^31 -1
143 
144     abs = ((frac >> 23) + 1) << (exp - 127);            //模拟
145     if (sign)
146         return -abs;
147     else
148         return abs;
149 }
150 
151 /****************************计算2*f***************************************/
152 unsigned float_twice(unsigned uf)
153 {
154     int result;
155     int exp = uf & 0x7f800000;
156     int frac = uf & 0x7fffff;
157     if (exp == 0x7f800000)
158         return uf;
159     else if (exp == 0)
160         frac = frac << 1;              //frac也可用uf代替,因为此时frac = uf
161     else
162         exp = exp + 0x800000;
163     result = (uf & 0x80000000) | exp | frac;
164     return result;
165 }      

个性签名:时间会解决一切