CSAPP:datalab實驗記錄

CSAPP:datalab實驗記錄

bitXor

/* 
 * bitXor - x^y using only ~ and & 
 *   Example: bitXor(4, 5) = 1
 *   Legal ops: ~ &
 *   Max ops: 14
 *   Rating: 1
 */

這道題的意思就是限定符號實現異或。我們很容易就知道:

\[a \oplus b = \overline a b + a \overline b \]

再化簡以下(邏輯代數的知識):

\[\overline a b + a \overline b = \overline { \overline {(a \overline b)} \overline {(\overline a b)}} \]

對照着實現就是:

int bitXor(int x, int y) {
  return ~(~(x & ~y) & ~(~x & y));
}

tmin

/* 
 * tmin - return minimum two's complement integer 
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 4
 *   Rating: 1
 */

補碼的最小值就是最高位位1咯,一個移位算法解決。

int tmin(void) {
  return 1 << 31;
}

isTMax

/*
 * isTmax - returns 1 if x is the maximum, two's complement number,
 *     and 0 otherwise 
 *   Legal ops: ! ~ & ^ | +
 *   Max ops: 10
 *   Rating: 1
 */

這道題有點難度。

首先,TMax 取反一定是TMinTMin 的特點就是取反加一是相同的。

而有一個特殊值0TMin 的特點是一樣的,需要排除。

所以,首先判斷是否等於,再將0 排除即可。

int isTmax(int x) {
	x = ~x;
  return !((~x + 1) ^ x) & !!(x ^ 0);
}

allOddBits

/* 
 * allOddBits - return 1 if all odd-numbered bits in word set to 1
 *   where bits are numbered from 0 (least significant) to 31 (most significant)
 *   Examples allOddBits(0xFFFFFFFD) = 0, allOddBits(0xAAAAAAAA) = 1
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 12
 *   Rating: 2
 */

這道題,我們可以先構造一個常數0xAAAAAAAA ,與x 取與之後,再與這個常數判斷是否相等即可。

int allOddBits(int x) {
	int temp = (0xAA << 24) + (0xAA << 16) + (0xAA << 8) + 0xAA;
  return !((temp & x) ^ temp);
}

negate

/* 
 * isAsciiDigit - return 1 if 0x30 <= x <= 0x39 (ASCII codes for characters '0' to '9')
 *   Example: isAsciiDigit(0x35) = 1.
 *            isAsciiDigit(0x3a) = 0.
 *            isAsciiDigit(0x05) = 0.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 15
 *   Rating: 3
 */

補碼的取反加一。(提醒一下這個取反加1,不是因爲首位是符號位,是因爲首位是負權值位!!!)

int negate(int x) {
  return (~x + 1);
}

isAsciiDigit

/* 
 * isAsciiDigit - return 1 if 0x30 <= x <= 0x39 (ASCII codes for characters '0' to '9')
 *   Example: isAsciiDigit(0x35) = 1.
 *            isAsciiDigit(0x3a) = 0.
 *            isAsciiDigit(0x05) = 0.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 15
 *   Rating: 3
 */

判斷範圍,一個數分別與這兩個常數相減,一正一負就是在範圍內。

正常思路是這樣,然而直接這麼實現的話,會有一個0x80000030 數據溢出,它與0x39 相減的時候溢出了。

嗯,所以我們不判斷首位是否不同了。與0x39 相減的地方我們改成-x 加上0x39 。然後判斷符號是否相同。就能避免溢出問題。

int isAsciiDigit(int x) {
  return !((x + ~0x30 + 1) >> 31) & !((~x + 0x39 + 1) >> 31);
}

conditional

/* 
 * conditional - same as x ? y : z 
 *   Example: conditional(2,4,5) = 4
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 16
 *   Rating: 3
 */

直接對x取非,就能得到對應的結果。再利用邏輯左移和算術右移,可以構造出一個0x0 或者是0xffffffff

就很簡單啦~

int conditional(int x, int y, int z) {
	x = (!x << 31) >>31;
  return (z & x) | (y & ~x);
}

isLessOrEqual

/* 
 * 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 x_sign = x >> 31;
	int y_sign = y >> 31;
  return (x_sign & !y_sign) | (!(x_sign ^ y_sign) & !((y + ~x + 1) >> 31));
}

logicalNeg

/* 
 * logicalNeg - implement the ! operator, using all of 
 *              the legal operators except !
 *   Examples: logicalNeg(3) = 0, logicalNeg(0) = 1
 *   Legal ops: ~ & ^ | + << >>
 *   Max ops: 12
 *   Rating: 4 
 */

只有0是要返回1的。所以~

只要首位是1,就是負,返回1。

其餘的所有正數加上TMax 都會溢出成負數。唯獨0不會。

所以~加上TMax 再康康符號位即可~

int logicalNeg(int x) {
	int Tmax = ~(0x1 << 31), sign = (x >> 31) & 0x1;
  return (sign | (((x + Tmax) >> 31) & 1)) ^ 0x1;
}

howManyBits

/* howManyBits - return the minimum number of bits required to represent x in
 *             two's complement
 *  Examples: howManyBits(12) = 5
 *            howManyBits(298) = 10
 *            howManyBits(-5) = 4
 *            howManyBits(0)  = 1
 *            howManyBits(-1) = 1
 *            howManyBits(0x80000000) = 32
 *  Legal ops: ! ~ & ^ | + << >>
 *  Max ops: 90
 *  Rating: 4
 */

這道題我不會,是參考別人的寫法完成的。二分法非常巧妙啊~

最難理解的當然就是負數的情況。不過想想還是能想明白。

這裏是利用二分法找到除了最高位以外的最高位。

整數很好說,關鍵是負數。由於補碼的特性,前面是可以有很多沒用的1的。所以負數是要找最高位的0哦~所以需要按照符號來取反。

int howManyBits(int x) {
	int sign, b1, b2, b4, b8, b16;
	sign = (x >> 31);
	x = (sign & ~x) | (~sign & x);
	b16 = !!(x >> 16) << 4;
	x = x >> b16;
	b8 = !!(x >> 8) << 3;
	x = x >> b8;
	b4 = !!(x >> 4) << 2;
	x = x >> b4;
	b2 = !!(x >> 2) << 1;
	x = x >> b2;
	b1 = !!(x >> 1);
	x = x >> b1;
  return b16 + b8 + b4 + b2 + b1 + x + 1;
}

floatScale2

/* 
 * floatScale2 - 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
 */

分情況判斷哦~

  1. 如果是0,直接返回;
  2. 如果階碼是0,直接左移一位。
  3. 如果階碼是最大值,直接返回(NaN,不用處理~)。

接下來就是普通情況。階碼自加1。

再次判斷,階碼達到最大值,直接返回不處理。

否則就將階碼拼接到原數據返回即可。

unsigned floatScale2(unsigned uf) {
	int e = (uf & 0x7f800000) >> 23;
	int sign = uf & (0x1 << 31);
	int M = (uf << 9) >> 9;
	if(M == 0 && e == 0) return uf;
	if(e == 0x0) return (uf << 1) | sign;
	if(e == 0xff) return uf;
	e++;
	if(e == 0xff && M > 0) return uf;
  return sign | (e << 23) | M;
}

floatFloat2Int

/* 
 * floatFloat2Int - Return bit-level equivalent of expression (int) f
 *   for floating point argument f.
 *   Argument is passed as unsigned int, but
 *   it is to be interpreted as the bit-level representation of a
 *   single-precision floating point value.
 *   Anything out of range (including NaN and infinity) should return
 *   0x80000000u.
 *   Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
 *   Max ops: 30
 *   Rating: 4
 */

根據浮點數的標準哈,將對應的數據分段拿下來~

嗯,如果是0直接返回0哈。

階碼處理一下,減一個偏移量。

如果階碼大於31,直接返回0x80000000

小於0,直接返回0.

而後面那一段數字,如果不處理的話,相當於就是自帶有一個值爲23的階碼。

所以,如果階碼大於23,就左移階碼多出的一段。小於23,就右移階碼少的一段。

int floatFloat2Int(unsigned uf) {
	int sign = uf >> 31;
	int exp = ((uf & 0x7f800000) >> 23) - 127;
	int M = (uf & 0x007fffff) | 0x00800000;
	if(!(uf & 0x7fffffff)) return 0;
	if(exp > 31) return 0x80000000;
	if(exp < 0) return 0;
	if(exp >23) M <<= (exp - 23);
	else M >>= (23 - exp);
	if(!((M >> 31) ^ sign)) return M;
	else if(M >> 31) return 0x80000000;
	else return ~M + 1;
}

floatPower2

/* 
 * floatPower2 - Return bit-level equivalent of the expression 2.0^x
 *   (2.0 raised to the power x) for any 32-bit integer x.
 *
 *   The unsigned value that is returned should have the identical bit
 *   representation as the single-precision floating-point number 2.0^x.
 *   If the result is too small to be represented as a denorm, return
 *   0. If too large, return +INF.
 * 
 *   Legal ops: Any integer/unsigned operations incl. ||, &&. Also if, while 
 *   Max ops: 30 
 *   Rating: 4
 */

2的次方嘛~傳入的參數就可以作爲階碼了。

階碼加上偏移。然後,階碼小於0,返回0。階碼大於255,返回無限大,否則直接返回階碼左移23位的值。就剛好是對應的答案。因爲當階碼不是0的時候自帶一個1嗷~

unsigned floatPower2(int x) {
	int inf;
	inf = 0xff << 23;
	x += 127;
	if(x <= 0) return 0x0;
	else if(x >= 255) return inf;
	return x << 23;
}

總結

位運算符號相等運算

這是在第三題學到的:

int equals(int x, int y){
    return !(x ^ y);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章