1. 程式人生 > 其它 >csapp data lab

csapp data lab

題目連結
完整答案在我的github

看到第四章要做個cpu的樣子,所以我打算把前面的實驗都補上
這是我第二次看csapp了,大一時候啥都不懂,看了三四章沒有體會到這本書的妙處,現在看時不時會爆出一句csapp nb!!

bitXor 這題很簡單就公式代換就好了

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

tmin 這題讓求最小值,根據csapp中對補碼的賦權可以知道最高位為1是最小值

/* 
 * tmin - return minimum two's complement integer 
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 4
 *   Rating: 1
 */
int tmin(void) {
  return 1 << 31;
}

isTmax 如果是最大值那麼就是除了最高位其餘為1,相加就是左移一位,然後再和本身相與,就構成了全1,不是最大值就構不成全1,其實這裡加1也行,然後再取反就是全0,再取邏輯非就是1

/*
 * isTmax - returns 1 if x is the maximum, two's complement number,
 *     and 0 otherwise 
 *   Legal ops: ! ~ & ^ | +
 *   Max ops: 10
 *   Rating: 1
 */
int isTmax(int x) {
  return !(~((x+x)&x));  //be -1 and ~ make it 0
}

allOddBits 判斷奇數位是否全為1,奇數位全1不就那一個數嗎,當然了這裡數的位數不確定,所以要與一次,擷取低位

/* 
 * 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
 */
int allOddBits(int x) { int num = 0xAA; num = num + (num << 8) + (num << 16) + (num << 24); return !(num ^ (x & num)); //與奇數位全為1的數與,再與正確答案異或,相等為0 }

negate 其實就是補碼

/* 
 * negate - return -x 
 *   Example: negate(1) = -1.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 5
 *   Rating: 2
 */
int negate(int x) {
  return ~x+1;      //補碼
}

isAsciiDigit 一個數是加上比0x39大的數後符號由正變負,另一個數是加上比0x30小的值時是負數,sign表示符號位

/* 
 * 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
 */
int isAsciiDigit(int x) {
  int sign = 0x1<<31;
  int upper = ~(sign|0x39);
  int lower = ~0x30;
  upper = sign&(upper+x)>>31;
  lower = sign&(lower+1+x)>>31;
  return !(upper|lower);
}

contional 當x為0時,和y與一個全0,對z與全1,當x不為0時相反

/* 
 * conditional - same as x ? y : z 
 *   Example: conditional(2,4,5) = 4
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 16
 *   Rating: 3
 */
int conditional(int x, int y, int z) {
  int val=(~0)+!x; //~(!!x)+1; 取bool值後若為0,則val為全0,否則全1
  return (val&y)|(~val&z);
}

isLessOrEqual 判斷兩種情況,小於和等於,可以通過相減,也就是加上補碼,減後x-y大於0就是x>y,正負通過符號位判斷,相等可以通過異或

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

logicalNeg 沒有!是重點,所以非0值要構造成0,可以通過構造全1,再加1,得到0,全1可以通過負數符號位為1,右移31位獲得,符號位為1可以通過原數和其對應的負數相或獲得

/* 
 * 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 
 */
int logicalNeg(int x) {
  return ((x | (~x + 1)) >> 31) + 1;
}

howManyBits 二分法,除了-1之外,其餘負數和其對應正數所需位數一樣,剩下用二分法,看高16位,8位,4位…

/* 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
 */
int howManyBits(int x) {
  int val1 = !(x ^ 0);          //is 0?
  int val2 = !(x ^ (~0));       //is -1?
  int val3 = ~(~(val1 | val2) + 1); //
  int bit_16, bit_8, bit_4, bit_2, bit_1;
	int sum;
	int op = x ^ (x >> 31);
	bit_16 = (!!(op >> 16)) << 4;  //!!把資料變為bool型
	op = op >> bit_16;
	bit_8 = (!!(op >> 8)) << 3;
	op = op >> bit_8;
	bit_4 = (!!(op >> 4)) << 2;
	op = op >> bit_4;
	bit_2 = (!!(op >> 2)) << 1;
	op = op >> bit_2;
	bit_1 = (!!(op >> 1));
	op = op >> bit_1;
	sum = 2 + bit_16 + bit_8 + bit_4 + bit_2 + bit_1;
  return val1 | val2 | (val3 & sum);
}

float 的三道題

/* 
 * 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
 */
unsigned floatScale2(unsigned uf) {
  int ret;
  int exp = uf & 0x7f800000;
  int frac = uf & 0x7fffff;
  if (exp == 0x7f800000)
    return uf;
  else if (exp == 0)
    frac = frac << 1;              
  else
    exp = exp + 0x800000;
  ret = (uf & 0x80000000) | exp | frac;
  return ret;
}
/* 
 * 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
 */
int floatFloat2Int(unsigned uf) {
  int exp = 0xff & (uf >> 23);
  int frac = 0x7fffff & uf;
  int sign = !!(uf >> 31);
  int tmp;

  if (exp > 127 + 30)
    return 0x80000000u;
  if (exp < 127)
    return 0;
  tmp = ((frac >> 23) + 1) << (exp - 127);
  if (sign)
    return (~tmp) + 1;
  else
    return tmp;
}
/* 
 * 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
 */
unsigned floatPower2(int x) {
  if (x < -127) return 0;
  if (x > 128) return 0xff << 23;
  return (x + 127) << 23;
}