深入理解計算機系統實驗LAB2實驗代碼及詳細實驗報告:datalab-handout.tar:填寫bits.c文件中尚未完成的各個函數的內容

題目來源:深入理解計算機系統實驗二

實驗題目:LAB2-datalab

實驗目的:通過此次實驗,進一步熟悉整型及浮點數的位表達形式,實現常用二進制運算的常用方法。

 

ReadmeFirst:

本次文件夾包括本次課程實驗LAB2的內容,內含2個文件:datalab-handout.tar以及ReadmeFirst.txt。

本次實驗內容經過在ubuntu12.04環境中測試,均可運行通過。

請詳細閱讀“datalab-handout.rar”包中的readme文件,瞭解實驗過程。

爲了便於大家理解實驗,在此簡述實驗過程:

首先,大家閱讀Readme文件,詳細瞭解實驗要求;

其次,本次實驗本質上是填寫bits.c文件中尚未完成的各個函數的內容。但是,本實驗要求只使用有限數量、規定的操作符。

第三,目錄下帶了dlc和btest兩個工具,用於檢測你所寫的函數代碼格式及功能是否正確(兩者的用法在readme中有介紹)。

 

一、    安裝VMware Tools並啓用共享文件夾

1.    安裝VMware Tools

1)    如圖,選擇【虛擬機】-【安裝VMware Tools】。

2)    若提示下圖信息,需要在【虛擬機設置】-【硬件】-【CD/DVD】中選擇【使用物理驅動器】。

3)    再次選擇【虛擬機】-【安裝VMware Tools】,等待數秒,彈出下圖所示界面。

4)    將gz文件複製到桌面。

5)    在終端cd進入桌面,如果無法輸入中文,可以ls-複製粘貼。


 
6)    在終端中鍵入”tar -zxvf <文件名>”,生成vmware-tools-distrib文件。

7)    鍵入cd vmware-tools-distrib

8)    鍵入”sudo ./vmware-install.pl”,輸入密碼,開始安裝過程

9)    安裝過程不斷鍵入回車,選擇默認安裝方式,直至安裝完成。

2.    啓用共享文件夾

1)    在【虛擬機設置】-【選項】-【共享文件夾】中添加共享文件夾。


2)    在虛擬機中的【文件系統】-【mnt】-【hgfs】可以查看共享的文件。


        在這裏我已經將實驗文件下載到共享文件夾。

二、    編寫bits.c

1.    實驗要求

一共 15個需要補充的函數,所有的工作都只需修改 bits.c 文件,然後通過btest, dlc和 BDD checker來測試代碼。

1)    一些小技巧:

① 在函數開始時聲明所有變量

② } 應該在第一行

③ 注意運算符號的優先級,使用括號確保順序的正確

④ 關注 !, 0, TMin 等

2)    任務指引主要有以下一些說明:

① 整型的範圍是 0 到 255(0xFF),不允許用更大

② 只能包含參數和局部變量

③ 一元操作符 ! ~

④ 二元操作符 & | + << >>

⑤ 不允許的操作有:

使用任何條件控制語句、定義和使用宏、定義其他的函數、調用函數、使用其他的操作符、使用類型轉換、使用除 int 之外的類型(針對整型)、使用除 int, unsigned 之外的類型(針對浮點數)

3)    可以認爲機器:

① 使用 2’s complent,32位

② 執行算術右移

③ 移動超過字長的位數會出問題

4)    其他需要注意的事情有:

① 使用 dlc(data lab checker) 來檢測代碼的合法性(有沒有使用不給使用的符號語法等等)

② 每個函數都有操作數的上限值,注意 = 不算

③ 使用 btest 來測試結果的正確與否

④ 使用 BDD checker 來正規測試你的函數

2.    bits.c

/* 
 * CS:APP Data Lab 
 * 
 * 
 * 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 constants.


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 functions 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 source.

/*
 * 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
 *   Algorithm:德摩根定律,~((~a)+(~b))=a&b,考慮到~爲位運算,因此得到的&爲位運算。 
 */
int bitAnd(int x, int y) {
	return ~( (~x) | (~y) ); 
}
/* 
 * 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
 *   Algorithm:1字節=8位,先利用n<<3得到n*8,再通過x右移運算,去掉最後的n*8位。 
 *   這樣,現在的x的最後8位即爲想要的結果。255的二進制表示爲0...011111111,因此將x與255按位 
 *   與, 就是最後結果。 
 */
int getByte(int x, int n) {
	n = n << 3; 
	x = x >> n;
	return (x & 255);
}
/* 
 * 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 
 *   Algorithm:邏輯右移將x的高n位置0。已有算術右移,只需要將移n位後的高n位改爲0即可。
 *   1 << 31得到100...,算術右移n位,得到1...10...0,共n+1位爲1。再左移1位,即可得到 *    
 *   1...10...0,共n位爲1。
 *   算術右移結果直接與0...01...1(高n位爲0)按位相與即可,目的temp爲0...01...1(高n位爲 *    
 *   0),因此temp按位取非。 
 */
int logicalShift(int x, int n) {
	int temp = ((1 << 31) >> n) << 1;
	temp = ~temp; 
	return (temp & (x >> n));
}
/*
 * bitCount - returns count of number of 1 in word
 *   Examples: bitCount(5) = 2, bitCount(7) = 3
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 40
 *   Rating: 4
 *   Algorithm:tmpMask1得到16位0101010...,tmpMask2得到16位00110011...,tmpMask3得到16 
 *   位00001111..., 
 *   因此mask分別得到對應tmpMask的32位結果。mask4爲32位0000000011111111...,mask5爲32位的 
 *   低16位全1。
 *   先計算x每兩位中1的個數,由count對應兩位存儲。以此類推,計算每4位、8位、16位中1的個數,
 *   最後的整合結果即爲x中的1的個數。每次“錯位”相當於一次相加。 
 */
int bitCount(int x) {
	int count = 0;
	int tmpMask1 = (0x55) | (0x55 << 8); 
	int mask1 = (tmpMask1) | (tmpMask1 << 16);
	int tmpMask2 = (0x33) | (0x33 << 8);
	int mask2 = (tmpMask2) | (tmpMask2 << 16);
	int tmpMask3 = (0x0f) | (0x0f << 8);
	int mask3 = (tmpMask3) | (tmpMask3 << 16);
	int mask4 = (0xff) | (0xff << 16);
	int mask5 = (0xff) | (0xff << 8);
	count = (x & mask1) + ((x >> 1) & mask1);
	count = (count & mask2) + ((count>>2) & mask2);
	count = (count + (count >> 4)) & mask3;
	count = (count + (count >> 8)) & mask4;
	count = (count + (count >> 16)) & mask5;
	return count;
}
/* 
 * bang - Compute !x without using !
 *   Examples: bang(3) = 0, bang(0) = 1
 *   Legal ops: ~ & ^ | + << >>
 *   Max ops: 12
 *   Rating: 4 
 *   Algorithm:只有當x=0時,~x爲全1,~x+1爲全0(逸出),x|(~x+1)的最高位爲0。只要x不爲0,x與 
 *   ~x+1的最高位一定有一個爲1, 
 *   可以用反證法證明這一點。因此,~(x|(~x+1))即爲結果。只需要將x|(~x+1)右移31位,與1按位 
 *   與,再按位取非即可。 
 */
int bang(int x) {
	int temp = x | (~x + 1);
	temp = ~(temp >> 31);
	return (temp & 1); 
}
/* 
 * tmin - return minimum two’s complement integer 
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 4
 *   Rating: 1
 *   Algorithm:即爲最高位爲1,其餘各位爲0。最高位爲符號位,負數,再減小一位即爲正數,因此是最小的整數。 
 */
int tmin(void) {
	int result = 1<<31;
	return result;
}
/* 
 * 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
 *   Algorithm:shift的值實際上是32-n,利用了補碼原理。將x先左移shift,再右移shift,其實是保留了低n位,其餘各位置0。
 *   將x與該值按位異或,只有當x的第31位~第n位全爲0時,按位異或的結果才爲0;否則便爲1。
 *   因此,只需要將按位異或的結果取非,即可得知x是否超過了n位二進制所能表示的範圍。 
 */
int fitsBits(int x, int n) {
	int anotherN = ~n + 1;
	int shift = 32 + anotherN;
	return !(x ^ (x << shift >> shift));
}
/* 
 * 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
 *   Algorithm:如果x爲整數,直接x>>n即爲正確結果,但由於代碼不能使用if語句,因此需要考慮其他方法。
 *   對於負數,除法是向0取整,而右移位是向負取整,因此需要加上偏置量2^n-1(低n-1位全爲1,其餘各位全爲0)。
 *   通過x>>31得到符號(全1或全0),與2^n-1按位與即可得到偏置量。x加上偏置量,向右移n位。 
 */
int divpwr2(int x, int n) {
	int sign = x >> 31;
	int mask = (1 << n) + (~0);
	return  (x + (sign & mask)) >> n;
}
/* 
 * negate - return -x 
 *   Example: negate(1) = -1.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 5
 *   Rating: 2
 *   Algorithm:求相反數,按位取反加一即可。如1,按位取反加一得到全1,即爲-1的補碼錶示。全1按位取反加一同樣得到1。 
 */
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
 *   Algorithm:判斷是否爲正數,看符號位即可。當x爲正數時,x>>31爲全0,!((x>>31)|(!x))即爲!!x,x不爲0時結果爲1。
 *   x爲負數時,x>>31爲全1,(x>>31)|(!x)爲全1,!((x>>31)|(!x))結果爲0。 
 */
int isPositive(int x) {
	return !((x >> 31) | (!x)); 
}
/* 
 * isLessOrEqual - if x <= y  then return 1, else return 0 
 *   Example: isLessOrEqual(4,5) = 1.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 24
 *   Rating: 3
 *   Algorithm:x小於等於y時返回1,其他情況返回0。通過右移31位後與1按位與,得到符號位。
 *   x<=y可以分解爲三種情況。第一種,x爲負數,y爲正數,即signx爲1,signy爲0。
 *   第二種,x與y同號,x小於y。通過x+((~y)+1)算得x-y,只需要判斷x-y的符號位即可! 
 *   第三種,x等於y,即x^y必爲全0,此時取非得1。 
 */
int isLessOrEqual(int x, int y) {
	int signx = (x >> 31) & 1;
	int signy = (y >> 31) & 1;
	int sign = (!signy) & signx;
	int tmp = x + ((~y) + 1);
	tmp = ((tmp >> 31) & 1) & (!(signx ^ signy));
	return (sign | tmp | ((!(x ^ y))));
}
/*
 * ilog2 - return floor(log base 2 of x), where x > 0
 *   Example: ilog2(16) = 4
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 90
 *   Rating: 4
 *   Algorithm:求log2(x),即判斷多少位二進制表示。
 *	 先將x右移16位i,若大於0,則先得到(10000)=16,否則得到0。
 *	 在現有數值的基礎上依次相加。x在現有bitsNumber的基礎上依次加8、4、2,相當於一個二分的過程,
 *	 每一步都是相同操作,即將x右移指定位數,由結果是否爲0,決定bitsNumber繼續加幾。 
 */
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)));
	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
 *   Algorithm:返回和-f相等的二進制,即取相反數。參數和返回結果都是無符號整數,但是可以解釋成單精度浮點數的二進制表示。
 *   0x80000000即爲最高位爲1,其餘爲0;0x7fffffff爲最高位爲0,其餘爲1。result將符號位改反,tmp將符號位改爲0。
 *   Nan>01111111100000000000000000000000對應的16進製表示爲0x7f800000。tmp爲Nan時,返回uf,否則返回result。 
 */
unsigned float_neg(unsigned uf) {
	unsigned result;
	unsigned tmp;
	result = uf ^ 0x80000000;
	tmp = uf & (0x7fffffff);
	if(tmp > 0x7f800000)
		result = uf;
	return result;
}
/* 
 * 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
 *   Algorithm:返回整型變量x的浮點數的二進制形式。當x=0時,返回0,當x小於0時,取sign爲1000...,absX爲其絕對值。
 *   絕對值不斷左移,shiftLeft記錄左移位數,直至最高位爲1爲止,afterShift爲左移後的結果。 
 *   0x01ff爲111111111,0x0100爲100000000, 判斷是否需要進位,如果需要,flag爲1。
 *   浮點數可以分爲三個部分,符號位、階碼、尾數。按無符號整數相加即可。 
 */
unsigned float_i2f(int x) {
	unsigned shiftLeft = 0;
	unsigned afterShift, tmp, flag;
	unsigned absX = x;
	unsigned sign = 0;
	if (x == 0)
		return 0;
	if (x < 0) {
		sign = 0x80000000;
		absX = -x;
	}
	afterShift = absX;
	while (1) {
		tmp = afterShift;
		afterShift = afterShift << 1;
		shiftLeft ++ ;
		if (tmp & 0x80000000)
			break;
	}
	if ((afterShift & 0x01ff) > 0x0100)
		flag = 1;
	else if ((afterShift & 0x03ff) == 0x0300)
	flag = 1;
	else
		flag = 0;
	return (sign + (afterShift >> 9) + ((159 - shiftLeft) << 23) + flag);
}
/* 
 * 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
 *   Algorithm:返回以unsinged表示的浮點數二進制的二倍的二進制unsigned型。 
 *   第一個if語句判斷非規格化的數。其中(f&0x007FFFFF)<<1作用爲當階碼全0時,令尾數左移。
 *  (0x80000000&f)將符號位恢復。第二個else if語句判斷規格化數。
 *   f=f+0x00800000即:若是規格化數,對它的階碼加1。如果都不滿足的話最後會返回uf原來的值。
 */
unsigned float_twice(unsigned uf) {
	unsigned f = uf;
	if ((f & 0x7F800000) == 0) {
		f = ((f & 0x007FFFFF) << 1) | (0x80000000 & f);
	}
	else if ((f & 0x7F800000) != 0x7F800000) {
		f = f + 0x00800000;
	}
	return f; 
}

 

三、    終端運行測試

1.    進入終端,cd進入共享文件夾。

2.    dlc測試程序是否通過編譯、符號的使用情況是否滿足要求

1)    在終端中輸入"./dlc bits.c"查看有無語法錯誤,輸入"./dlc -e bits.c"查看符號使用情況。
 
2)    輸入"make btest",執行makeFile操作。
 
3)    輸入"./btest [optional cmd line args]"查看bits.c各個功能的實現情況。
 
4)    Something else

鍵入"./btest -h"可以查看其它命令的說明。

鍵入"./ishow <數字>"可以幫助我們進一步理解int的存儲。

鍵入"./fshow <數字>"可以幫助我們進一步理解float的存儲。

 

實驗結果及分析:

實驗結果達到預期,15個程序均滿足題目對符號和常數的限制要求;15個程序均運行正確,41分全部得到。

MakeFile以及通過btest、dlc測試代碼等基本操作熟練掌握。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章