深入理解计算机系统配套实验(一) data lab 函数详解

/*   
135. * bitAnd - x&y using only ~ and |   
136. *   Example: bitAnd(6, 5) = 4  
137. *   Legal ops: ~ |  
138. *   Max ops: 8  
139. *   Rating: 1  
140. */  
141.int bitAnd(int x, int y) {  
142.  
143.  return ~(~x|~y);  
144.}  

这是第一个函数,看描述是要我们仅使用~和|实现&的功能。还记得离散数学上学的摩根定律吗,x&y = ~(~x|~y) ,所以第一个是比较简单的。

/*   
146. * getByte - Extract byte n from word x  
147. *   Bytes numbered from 0 (LSB) to 3 (MSB)  
148. *   Examples: getByte(0x12345678,1) = 0x56  
149. *   Legal ops: ! ~ & ^ | + << >>  
150. *   Max ops: 6  
151. *   Rating: 2  
152. */  
153.int getByte(int x, int n) {  
154.  
155.  return x>>(n<<3)&0xff;  
156.  
157.}  

第二个函数,实现向返回第几字节的操作。需要知道的是两个数字占一个字节。而八个数字即是四个字节,双字。所以n只能从0到3取。第0位是最低位,例子里即是78,3为最高位,存的是12,以此类推。所以要返回第n位的数字,我们需要做的是右移挤掉比n低的数位,并且忽略掉比n高的数位。所以我们先做右移操作,需要注意的是移位的时候是按照二进制移位的,所以要先将n乘8,即n<<3,然后再右移。右移之后我们需要的数字就是最低位了,再和0xff做与运算,就可以把高位的数位全部忽略掉。

/*   
159. * logicalShift - shift x to the right by n, using a logical shift  
160. *   Can assume that 0 <= n <= 31  
161. *   Examples: logicalShift(0x87654321,4) = 0x08765432  
162. *   Legal ops: ! ~ & ^ | + << >>  
163. *   Max ops: 20  
164. *   Rating: 3   
165. */  
166.int logicalShift(int x, int n) {  
167.  
168.  return (x>>n)&(~((0x1<<31)>>n<<1));  
169.}  

第三个函数,实现逻辑右移。计算机在右移的时候会对有符号数进行算术右移(补齐最高有效位),对无符号数进行逻辑右移。这个函数要实现的是无条件的逻辑右移,也即我们需要做的是将右移的数与0x00…11做与运算,其中0的个数等同于右移位数。所以我们需要的是~(1<<31)>>n<<1[不能使用-号,所以不是n-1],所以结果是(x>>n)&(~(1<<31)>>n<<1).

/*  
171. * bitCount - returns count of number of 1's in word  
172. *   Examples: bitCount(5) = 2, bitCount(7) = 3  
173. *   Legal ops: ! ~ & ^ | + << >>  
174. *   Max ops: 40  
175. *   Rating: 4  
176. */  
177. /*  
178. **参考《CSAPP深入理解计算机系统》例3.50解答  
179. */  
180.int bitCount(int x) {  
181.  int c;
182. c=(x&0x55555555)+(x>>1&0x55555555);
183. c=(c&0x33333333)+(c>>2&0x33333333);
184. c=(c&0x0f0f0f0f)+(c>>4&0x0f0f0f0f);
185. c=(c&0x00ff00ff)+(c>>8&0x00ff00ff);
186. c=(c&0x0000ffff)+(c>>16&0x0000ffff);
187. return c
}  

第四题要求返回二进制数中1的个数。参考深入理解3.50。我认为这个函数的难度较大,我参考了这个论坛的内容https://stackoverflow.com/questions/3815165/how-to-implement-bitcount-using-only-bitwise-operators。有兴趣的同学可以看一下,我觉得还是能看懂的

/*   
195. * bang - Compute !x without using !  
196. *   Examples: bang(3) = 0, bang(0) = 1  
197. *   Legal ops: ~ & ^ | + << >>  
198. *   Max ops: 12  
199. *   Rating: 4   
200. */  
201./*  
202.**If x!=0,x+(~x+1)=2^32,the highest bit of x and (~x+1)cannot be both 0(至少有一个为1再加上进位就可以继续进位,否则不会变成2^32).  
203.*/  
204.int bang(int x) {  
205.  return (~((x|(~x+1))>>31))&0x1;  
206.}  

x+~x+1 =2^32,当x不为0时,x和~x+1的最高位不可能同时为0。这个性质是我们解题的关键,我们只要将这两者做或运算,就能得到“x不为0时,最高位为1”和“x为0时,最高为为0“的性质,这时候我们再将结果右移31位,只保留最高位,再取反,与1做与运算就能得到我们想要的结果了。

```
/*   
208. * tmin - return minimum two's complement integer   
209. *   Legal ops: ! ~ & ^ | + << >>  
210. *   Max ops: 4  
211. *   Rating: 1  
212. */  
213.int tmin(void) {  
214.  return 0x1<<31;  
215.}  

不多解释

/*   
217. * fitsBits - return 1 if x can be represented as an   
218. *  n-bit, two's complement integer.  
219. *   1 <= n <= 32  
220. *   Examples: fitsBits(5,3) = 0, fitsBits(-4,3) = 1  
221. *   Legal ops: ! ~ & ^ | + << >>  
222. *   Max ops: 15  
223. *   Rating: 2  
224. */  
225./* if all negative numbers(e.g x) are changed into ~x, all the numbers those   
226.   * can be represented as an n-bit, two's complement integer will be in range   
227.   * of 0~2^(n-1). If it was arithmatically shifted (n-1) bits to right, it'll  
228.   * be 0x00000000.   
229.   http://codejam.diandian.com/post/2011-04-16/427784  
230.*/  
231.int fitsBits(int x, int n) {  
    int shiftNumber= 32 + (~n + 1);// 32 - n
    return !(x^((x<>shiftNumber));35.}  

先左移32-n位,在右移32-n位,即保留最后n位数。在与x异或
若两者相同表示x可被表示为一个n位整数,!0为1

/*   
237. * divpwr2 - Compute x/(2^n), for 0 <= n <= 30  
238. *  Round toward zero  
239. *   Examples: divpwr2(15,1) = 7, divpwr2(-33,4) = -2  
240. *   Legal ops: ! ~ & ^ | + << >>  
241. *   Max ops: 15  
242. *   Rating: 2  
243. */  
244.int divpwr2(int x, int n) {  
245.    int sign=x>>31;  
246.    int bias=sign & ((1<0));  
247.    return (x+bias)>>n;  
248.}  

这个函数实现除以2^n的操作,如果x为正数直接移位,如果为负数,则加上偏置量后再移位。有关补码除法和偏置量的内容,详见深入理解

/*   
250. * negate - return -x   
251. *   Example: negate(1) = -1.  
252. *   Legal ops: ! ~ & ^ | + << >>  
253. *   Max ops: 5  
254. *   Rating: 2  
255. */  
256.int negate(int x) {  
257.  return ~x+1;  
258.}  

补码+1即为相反数,有关补码内容强烈推荐看百度百科

/*   
260. * isPositive - return 1 if x > 0, return 0 otherwise   
261. *   Example: isPositive(-1) = 0.  
262. *   Legal ops: ! ~ & ^ | + << >>  
263. *   Max ops: 8  
264. *   Rating: 3  
265. */  
266.int isPositive(int x) {  
267.  return !((x>>31)|(!x));  
268.}  

两种情况返回0 等于0 或者 小于0,所以返回标志位的非或者非0的非(0的标志位是0)

/*   
270. * isLessOrEqual - if x <= y  then return 1, else return 0   
271. *   Example: isLessOrEqual(4,5) = 1.  
272. *   Legal ops: ! ~ & ^ | + << >>  
273. *   Max ops: 24  
274. *   Rating: 3  
275. */  
276./* Because the substraction of two numbers with different signs may cause   
277.   * overflow, we should only judge whether x is negative then return   
278.   * 1(true). Otherwise we'll judge whether (x-y) is a non-positive  
279.     ((x+(~y)+1-1)>>31,which includes the situation of x-y=0)  
280.   * number and return 1(true).   
281.   reference:http://codejam.diandian.com/post/2011-04-16/427885   
282.*/  
283.int isLessOrEqual(int x, int y) {  
284.  int signx=x>>31;  
285.  int signy=y>>31;  
286.  int IsSameSign=(!(signx^signy));  
287.  return (IsSameSign & ((x+(~y))>>31)) | ((!IsSameSign) & signx);  
288.}  

比较大小,如果x是负,y是正就直接返回1,如果相同再做比较。所以设置一个IsSameSign,相同时,如果x<=y,则x-y<=0,那么x-y-1 < 0,故我们用x+~y再取其标志位就能得到想要的结果,如果不相同,那么只需要取x的标志位为1的情况即可。这两种情况或运算并起来即可

```
/*  
290. * ilog2 - return floor(log base 2 of x), where x > 0  
291. *   Example: ilog2(16) = 4  
292. *   Legal ops: ! ~ & ^ | + << >>  
293. *   Max ops: 90  
294. *   Rating: 4  
295. */  
296.  /* ilog2 is equivlance of finding the index of first 1 from left, the method is as following:  
297.   * check whether x's left half bits are all 0's, if so then throw them away,   
298.   * else right shift to reject the right half(remember the 16 bits thrown from   
299.   * right), to repeat it until only one "1" remaining and return the remembered  
300.   * number of x having been eliminated.   
301.    http://codejam.diandian.com/post/2011-04-16/428134  
302.   */  
303.int ilog2(int x) {  
 int bitsNumber=0;
    bitsNumber=(!!(x>>16))<<4;//
    bitsNumber=bitsNumber+((!!(x>>(bitsNumber+8)))<<3);
    bitsNumber=bitsNumber+((!!(x>>(bitsNumber+4)))<<2);
    bitsNumber=bitsNumber+((!!(x>>(bitsNumber+2)))<<1);
    bitsNumber=bitsNumber+(!!(x>>(bitsNumber+1)));
    //for non zero bitsNumber, it should add 0
    //for zero bitsNumber, it should subtract 1
    bitsNumber=bitsNumber+(!!bitsNumber)+(~0)+(!(1^x));
    //当x为0时,还需要减一才能得到正确值。
    return bitsNumber;
/*   
330. * float_neg - Return bit-level equivalent of expression -f for  
331. *   floating point argument f.  
332. *   Both the argument and result are passed as unsigned int's, but  
333. *   they are to be interpreted as the bit-level representations of  
334. *   single-precision floating point values.  
335. *   When argument is NaN, return argument.  
336. *   Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while  
337. *   Max ops: 10  
338. *   Rating: 2  
339. */  
340.unsigned float_neg(unsigned uf) {  
341.  unsigned result= uf ^ 0x80000000;//change the signed bit of uf  
342.  unsigned tmp=uf & 0x7fffffff;//change the signed bit of uf to 0  
343.  if( tmp > 0x7f800000 ) //When argument is NaN(exponent bits are all 1 and mantissa bits arenot all 0), return argument.  
344.                         //IEEE754 standard:1 bit signed bit,8 bits exponent,23 bits mantissa.  
345.      result=uf;  
346. return result;  
347.}  
348./*   

将符号位改反即可,只需要多考虑NaN的情况即可,关于NaN,详见深入理解

* float_i2f - Return bit-level equivalent of expression (float) x  
350. *   Result is returned as unsigned int, but  
351. *   it is to be interpreted as the bit-level representation of a  
352. *   single-precision floating point values.  
353. *   Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while  
354. *   Max ops: 30  
355. *   Rating: 4  
356. */  
357.unsigned float_i2f(int x) {//Rounding is important!  
358.  unsigned sign=0,shiftleft=0,flag=0,tmp;  
359.  unsigned absx=x;  
360.  if( x==0 ) return 0;  
361.  if( x<0 ){  
362.     sign=0x80000000;  
363.     absx=-x;  
364.  }  
365.  while(1){//Shift until the highest bit equal to 1 in order to normalize the floating-point number  
366.     tmp=absx;  
367.     absx<<=1;  
368.     shiftleft++;  
369.     if( tmp&0x80000000 ) break;  
370.  }  
371.  if( (absx & 0x01ff) > 0x0100 ) flag=1;//***Rounding 1  
372.  if( (absx & 0x03ff) == 0x0300 ) flag=1;//***Rounding 2  
373.    
374.  return sign+(absx>>9)+((159-shiftleft)<<23)+flag;  
375.}  

详见深入理解有关浮点数一章的讲解,仔细理解即可。

```
/*   
377. * float_twice - Return bit-level equivalent of expression 2*f for  
378. *   floating point argument f.  
379. *   Both the argument and result are passed as unsigned int's, but  
380. *   they are to be interpreted as the bit-level representation of  
381. *   single-precision floating point values.  
382. *   When argument is NaN, return argument  
383. *   Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while  
384. *   Max ops: 30  
385. *   Rating: 4  
386. */  
387.unsigned float_twice(unsigned f) {  
unsigned f = f;
    if ((f & 0x7F800000) == 0) // 
    {
        //左移一位
        f = ((f & 0x007FFFFF) << 1) | (0x80000000 & f);
    }
    else if ((f & 0x7F800000) != 0x7F800000)
    {
        f =f + 0x00800000;
    }
    return f;

同上

你可能感兴趣的:(深入理解计算机系统配套实验(一) data lab 函数详解)