1. 程式人生 > >CSAPP lab1 datalab-handout(深入瞭解計算機系統 實驗一)

CSAPP lab1 datalab-handout(深入瞭解計算機系統 實驗一)

能看懂的就不寫註釋了

        /* 
 * CS:APP Data Lab 
 * 
 * <Please put your name and userid here>
 * 
 * bits.c - Source file with your solutions to the Lab.
 *          This is the file you will hand in to your instructor.
 *
 * WARNING: Do not include the <stdio.h> header; it confuses the dlc
 * compiler. You can still use printf for debugging without including
 * <stdio.h>, although you might get a compiler warning. In general,
 * it's not good practice to ignore compiler warnings, but in this
 * case it's OK.  
 */


#if 0
/*
 * Instructions to Students:
 *
 * STEP 1: Read the following instructions carefully.
 */


You will provide your solution to the Data Lab by
editing the collection of functions in this source file.


INTEGER CODING RULES:
 
  Replace the "return" statement in each function with one
  or more lines of C code that implements the function. Your code 
  must conform to the following style:
 
  int Funct(arg1, arg2, ...) {
      /* brief description of how your implementation works */
      int var1 = Expr1;
      ...
      int varM = ExprM;


      varJ = ExprJ;
      ...
      varN = ExprN;
      return ExprR;
  }


  Each "Expr" is an expression using ONLY the following:
  1. Integer constants 0 through 255 (0xFF), inclusive. You are
      not allowed to use big constants such as 0xffffffff.
  2. Function arguments and local variables (no global variables).
  3. Unary integer operations ! ~
  4. Binary integer operations & ^ | + << >>
    
  Some of the problems restrict the set of allowed operators even further.
  Each "Expr" may consist of multiple operators. You are not restricted to
  one operator per line.


  You are expressly forbidden to:
  1. Use any control constructs such as if, do, while, for, switch, etc.
  2. Define or use any macros.
  3. Define any additional functions in this file.
  4. Call any functions.
  5. Use any other operations, such as &&, ||, -, or ?:
  6. Use any form of casting.
  7. Use any data type other than int.  This implies that you
     cannot use arrays, structs, or unions.


 
  You may assume that your machine:
  1. Uses 2s complement, 32-bit representations of integers.
  2. Performs right shifts arithmetically.
  3. Has unpredictable behavior when shifting an integer by more
     than the word size.


EXAMPLES OF ACCEPTABLE CODING STYLE:
  /*
   * pow2plus1 - returns 2^x + 1, where 0 <= x <= 31
   */
  int pow2plus1(int x) {
     /* exploit ability of shifts to compute powers of 2 */
     return (1 << x) + 1;
  }


  /*
   * pow2plus4 - returns 2^x + 4, where 0 <= x <= 31
   */
  int pow2plus4(int x) {
     /* exploit ability of shifts to compute powers of 2 */
     int result = (1 << x);
     result += 4;
     return result;
  }


FLOATING POINT CODING RULES


For the problems that require you to implent floating-point operations,
the coding rules are less strict.  You are allowed to use looping and
conditional control.  You are allowed to use both ints and unsigneds.
You can use arbitrary integer and unsigned constants.


You are expressly forbidden to:
  1. Define or use any macros.
  2. Define any additional functions in this file.
  3. Call any functions.
  4. Use any form of casting.
  5. Use any data type other than int or unsigned.  This means that you
     cannot use arrays, structs, or unions.
  6. Use any floating point data types, operations, or .




NOTES:
  1. Use the dlc (data lab checker) compiler (described in the handout) to 
     check the legality of your solutions.
  2. Each function has a maximum number of operators (! ~ & ^ | + << >>)
     that you are allowed to use for your implementation of the function. 
     The max operator count is checked by dlc. Note that '=' is not 
     counted; you may use as many of these as you want without penalty.
  3. Use the btest test harness to check your function for correctness.
  4. Use the BDD checker to formally verify your functions
  5. The maximum number of ops for each function is given in the
     header comment for each function. If there are any inconsistencies 
     between the maximum ops in the writeup and in this file, consider
     this file the authoritative sourc.


/*
 * STEP 2: Modify the following functions according the coding rules.
 * 
 *   IMPORTANT. TO AVOID GRADING SURPRISES:
 *   1. Use the dlc compiler to check that your solutions conform
 *      to the coding rules.
 *   2. Use the BDD checker to formally verify that your solutions produce 
 *      the correct answers.
 */




#endif
/* 
 * bitAnd - x&y using only ~ and | 
 *   Example: bitAnd(6, 5) = 4
 *   Legal ops: ~ 
 *   Max ops: 8
 *   Rating: 1
 */
int bitAnd(int x, int y) {
	int ret = ~(~x | ~y);
  return ret;
}
/* 
 * 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) {


	int ret = (x >> (n<<3)) & 0XFF;


  return ret;


}
/* 
 * 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 ret = (x >> n) & (~(((1<<31)>>n)<<1));
  return ret;
}
/*
 * 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 tmp = (0x55)|(0x55 << 8);
	int mask1 = tmp | (tmp << 16);
	int mask2 = 0;
	int mask3 = 0;
	int mask4=(0xFF)|(0xFF<<16);         
	int mask5=(0xFF)|(0xFF<<8);
	int result = 0;
	
	tmp = (0x33)|(0x33 << 8);
	mask2 = tmp | (tmp << 16);
	tmp = (0x0F)|(0x0F << 8);
	mask3 = tmp | (tmp << 16);
	 
	
	result=(x&mask1)+((x>>1)&mask1);          
	result=(result&mask2)+((result>>2)&mask2);         
	result=(result+(result>>4))&mask3;         
	result=(result+(result>>8))&mask4;         
	result=(result+(result>>16))&mask5;
	
	return result;
}
/* 
 * bang - Compute !x without using !
 *   Examples: bang(3) = 0, bang(0) = 1
 *   Legal ops: ~ & ^ | + << >>
 *   Max ops: 12
 *   Rating: 4 
 */
int bang(int x) {
  int ret = (~((x | (~x +1)) >> 31)) & 1;
  return ret;
}
/* 
 * tmin - return minimum two's complement integer 
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 4
 *   Rating: 1
 */
int tmin(void) {
  return (1<<31);
}
/* 
 * 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 shift_cnt = ~n +33;
  return !(x^((x<<shift_cnt)>>shift_cnt));
}
/* 
 * 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) {
		int mask = (~0)+(1<<n);
		
		int bias = (x>>31)&mask;
		
    return (x+bias)>>n;
}
/* 
 * negate - return -x 
 *   Example: negate(1) = -1.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 5
 *   Rating: 2
 */
int negate(int x) {
  return (~x) + 1;
}
/* 
 * 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) & 0x01)) & (!!(x));
}
/* 
 * 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 signEqual = (!(signx ^signy)) & ((x+(~y))>>31);
	int signDiffer=signx&(!signy); 
  return signEqual|signDiffer;
}
/*
 * 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) {
  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)));         
  bitsNumber=bitsNumber+(!!bitsNumber)+(~0)+(!(1^x));         
  return bitsNumber;
}
/* 
 * 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 res = 0;
	unsigned tmp = 0;
	
	tmp = uf & 0x7fffffff;
	res = uf ^ 0x80000000;
	
	if(tmp > 0x7f800000)
		res = uf;
		
  return res;
}
/* 
 * 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 x) {
  
    int sign=x>>31&1;//獲取符號位(1位)
    int i;
    int exponent; //指數域(8位)
    int fraction; //小數域
    int delta;//偏差(用於舍入)
    int fraction_mask;//小數域的掩碼(23位)
    if(x==0)//如果為0就直接返回
        return x;
    else if(x==0x80000000)//如果為TMin,解釋為-(2^31),對應float就是(1)x1.0x2^31,所以S=1,M=1,E=31,指數域=31+127=158
        exponent=158;
    else{
        if (sign)//通過前面的操作已經確定了符號,先把int的絕對值獲取,之後利用浮點數的計算公式即可計算出float的值,現在要獲取絕對值存入記憶體中
            x = -x;
        
        i = 30;//最高位是符號位,次高位是有效數字的起始位
        while ( !(x >> i) )//從左往右查詢有效數字第一個不為零的位,對應的位置就是最終的i(這裡的位置從0開始標號)
            i--;
        //printf("%x %d\n",x,i);
        exponent = i + 127;//數值的最高位已經找到是第i位(有效資料共有i+1位),又因為int型別不可能是非規格資料的範圍(為0的情況在前面已排除),所以小數域就是d第i為後面的位向量(小數域一共有i個位),故階碼E=i(小數部分x2的E次方),指數域等於i+127;
        x = x << (31 - i);//清除有效資料前面的所有0,包括符號位,得到有效資料開頭的資料
        fraction_mask = 0x7fffff;//設定23位的小數域掩碼
        fraction = fraction_mask & (x >> 8);//雖然按照浮點數格式,最前面的9個位不加入小數位,按道理應該右移9位,
        																		//但是由於int型別的引數不可能是非規格數,所以最前面的一個有效資料也被捨棄(預設M=1+f),
        																		//當向右移動8位,捨棄了有效資料的低8位,再和掩碼處理以後,一共捨棄了9位
        																		//除了低八位還包括有效資料的最高位,類比二進位制小數中小數點左邊的那一位數字,在float儲存的時候,小數點左邊數字不存入記憶體
        																		//者9個位用來儲存符號位+指數域
        x = x & 0xff;//由於右移8位,捨棄了有效資料第八位,現在獲取低八位用於舍入操作
        delta = x > 128 || ((x == 128) && (fraction & 1));//如果低八位超過八位二進位制能表示的無符號數的一半,
        																									//要在小數域+1,普通的四捨五入思想
        																									//如果低八位剛好等於八位二進位制能表示的無符號數的一半,而且小數域目前最後一位是1,
        																									//根據向偶數舍入的模式,也要在小數域+1,向上舍入的思想,
        																									//如果低八位剛好等於八位二進位制能表示的無符號數的一半,如果小數域目前最後一位是0,則向下舍入,不加1
        																									//如果低八位剛好小於八位二進位制能表示的無符號數的一半,直接丟棄,不加1,普通的四捨五入思想
        fraction += delta;//進行舍入
        if(fraction >> 23) {//如果舍入過後,小數域多餘23位,則只取低23位,高位捨棄,但是階碼E要加1,所以指數域也就要加1
            fraction &= fraction_mask;
            exponent += 1;
        }
    }
    return (sign<<31)|(exponent<<23)|fraction;//符號位最高位(31),指數域(30--23),小數域(22-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(unsigned uf) {
  unsigned res = uf;
	
	if((res & 0x7F800000) == 0)
		{
				res = ((res & 0x007FFFFF)<<1) | (res & 0x80000000);	
		}
	else if((res & 0x7F800000) != 0x7F800000)
		{
			  res = res+0x00800000;
		}	
		
  return res;
}


關於統計二進位制中1的位數,詳細的解釋可以引用於stackOverflow

http://stackoverflow.com/questions/3815165/how-to-implement-bitcount-using-only-bitwise-operators

unsignedint v;// count bits set in this (32-bit value)unsignedint c;// store the total here

c = v -((v >>1)&0x55555555);
c =((c >>2)&0x33333333)+(c &
0x33333333); c =((c >>4)+ c)&0x0F0F0F0F; c =((c >>8)+ c)&0x00FF00FF; c =((c >>16)+ c)&0x0000FFFF;

Edit: Admittedly it's a bit optimized which makes it harder to read. It's easier to read as:

c =(v &0x55555555)+((v >>1)&0x55555555);
c =(c &0x33333333)+((c >>2)&
0x33333333); c =(c &0x0F0F0F0F)+((c >>4)&0x0F0F0F0F); c =(c &0x00FF00FF)+((c >>8)&0x00FF00FF); c =(c &0x0000FFFF)+((c >>16)&0x0000FFFF);

Each step of those five, adds neighbouring bits together in groups of 1, then 2, then 4 etc. The method is based in divide and conquer.

In the first step we add together bits 0 and 1 and put the result in the two bit segment 0-1, add bits 2 and 3 and put the result in the two-bit segment 2-3 etc...

In the second step we add the two-bits 0-1 and 2-3 together and put the result in four-bit 0-3, add together two-bits 4-5 and 6-7 and put the result in four-bit 4-7 etc...

Example:

Soif I have number 395 in binary 0000000110001011(0000000110001011)After the first step I have:0000000101000110(0+00+00+00+11+00+01+01+1)=0000000101000110In the second step I have:0000000100010011(00+0000+0101+0001+10)=0000000100010011In the fourth step I have:0000000100000100(0000+00010001+0011)=0000000100000100In the last step I have:0000000000000101(00000001+00000100)

which is equal to 5, which is the correct result


再附上幾個參考資料

http://wdxtub.com/2016/04/16/thick-csapp-lab-1/

http://wenku.baidu.com/link?url=00k0funtVK1IHYJvtqV-zeywPEWCXf852MxbtxL3WXrFeh7LTUZgBk1ycW9yay5zLC8y20TjSawNKwQ3qSX5Z6XxMlkroBehcRlU3z5i8cS