1 實驗說明
從CSAPP課程主頁下載datalab實驗所需的壓縮包。下圖說明本次實驗需要補齊的函數名列表。
2 實驗
2.1
/*
* 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));
}
解題思路:
利用a⊕b = (¬a ∧ b) ∨ (a ∧¬b)公式和德-摩根定律得到上面的代碼.
2.2
/*
* tmin - return minimum two's complement integer
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 4
* Rating: 1
*/
int tmin(void) {
return 0x1<<31;
}
解題思路:
首先明確32位整數最小值的二進制爲0x80000000.
2.3
/*
* 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) {
int res = !((~(x+1))^x) & !!(~x);
return res ;
}
解題思路:
首先明確32位整形最大值爲0x7fffffff.由於題目中規定不能使用移位符號,
2.4
/*
* 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 mask = 0xAA | (0xAA<<8) | (0xAA<<16) | (0xAA <<24);
x = x & mask;
return !~(x>>1 | x);
}
解題思路:
首先要獲取奇數位的信息,則有mask:0xAAAAAAAA.(十六進制A的二進制表示爲1010).當奇數位全爲1時,(x>>1 | x)則表示0xffffffff,反之,則不成立.
2.5
/*
* negate - return -x
* Example: negate(1) = -1.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 5
* Rating: 2
*/
int negate(int x) {
return ~x+1;
}
解題思路:
套基本公式
2.6
/*
* 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) {
return !((0x39 + (~x+1))>>31|(x+(~0x30+1))>>31)&0x1;
}
解題思路:
題目的等價表達式是"(0x39-x)>=0且(x-0x30)>=0".此時只需要判斷符號位就能知道是否滿足不等式(符號位爲1表示不滿足),這與函數輸出的邏輯剛好相反(函數輸出1表示滿足整個表達式).最後利用的摩根定理得到上述代碼.
2.7
/*
* 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 x1 = ~((~x +1)|x)>>31;
return (~x1 & y ) | (x1 & z);
}
解題思路:
題目讓我們寫一個條件選擇符,當x爲0x0時選擇輸出z,考慮利用零的相反數是零的性質解題.
2.8
/*
* 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 signal = signx ^ signy;
int exp = ((y+(~x+1))>>31);
return ((signal&( (signx&0x1) | (signy&0x0) ) ) | (!signal&!exp ))&0x1;
}
解題思路:
等價爲y-x>=0,有四類情況分類討論
2.9
/*
* 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+1)|x)>>31)& 0x1;
}
2.10
/* 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
*/
/*
* -5 1,000_0000_0000_0000_0000_0000_0000_0101 1111_1111_1111_1111_1111_1111_1111_1011
* 5 0,000_0000_0000_0000_0000_0000_0000_0101
* */
int howManyBits(int x) {
int mask1 = 0x1 | 0x1<<8 | 0x1<<16 | 0x1<<24;
int mask2 = (x&(0x1<<31))>>31;
int sum = 0;
int tmp = x ^ mask2;
tmp |= tmp >>1;
tmp |= tmp >>2;
tmp |= tmp >>4;
tmp |= tmp >>8; sum += (tmp >>2) & mask1;
sum += (tmp >>3) & mask1;
sum += (tmp >>4) & mask1;
sum += (tmp >>5) & mask1;
sum += (tmp >>6) & mask1;
sum += (tmp >>7) & mask1;
return (sum & 0xff) + ((sum>>8) & 0xff) + ((sum>>16) & 0xff) + ((sum>>24) & 0xff) + 1;
}
解題思路:
忽略符號位,把最高位的1右側所有位都置爲1,再查詢1的個數,最中的結果再加1.
2.11
/*
* 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) {
unsigned sign = uf & 0x80000000;
unsigned exp = uf & 0x7f800000;
unsigned frac = uf & 0x7fffff;
if(exp ^ 0x7f800000){//exp!=255
if(!exp){//exp==0
frac <<= 1;//此時爲非規格化數,尾數無隱含常數1,直接左移1位即可
}
else{//0<exp<255
exp += 0x800000;//乘2
if((exp ^ 0x7f800000)==0){//判斷乘2以後是否溢出
frac=0;//輸出INF
}
}
}
return sign | exp | frac;
}
解題思路:
接下來的三題,讓我深刻理解了"數據類型規定了數的爲寬,和相應的操作方法"這句話的意義.下圖表示了浮點數的位級示意圖.從圖可以知道解答lab中關於浮點數的題目.
2.12
/*
* 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) {
unsigned INF = 0x80000000;
//提取符號位
int s = (uf >>31) & 0x1;
//提取階碼
int E = uf >> 23 & 0xff;
//提取階數
int e = E -127;
if (uf == 0) return 0;
//因爲輸入是規格化浮點數,轉化爲整數時第23位需要爲1
uf &= 0x00ffffff;
uf |= 0x00800000;
//浮點數中0~22位的數字邏輯上位小數,當看作整數時相當於乘以了2^23
//階碼爲255或階數大於等於32時,視爲溢出,輸出INF.因爲int爲32bit,超出即溢出,且考慮1bit符號位
if ((uf & 0x7f80000) == 0x7f80000 || e>= 32) return INF;
if (e<0) return 0;//若爲小數,返回零
//無符號數的移位運算都是邏輯移位
if (e <= 23) uf >>= 23 - e;//因爲浮點數尾數寬度爲23bit,位數小於等於23,尾數位右移.這是一種舍入方式
else uf <<= e-23;//位數大於23,尾數左移
//當符號位爲負數,uf要取值爲它的相反數
if(s) uf = ~uf + 1;
return uf;
}
2.13
/*
* 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) {
//int INF = 0xff << 23;
int INF = 0x7f800000;
int exp = x + 127 ;
//溢出
if(exp >= 255) return INF;
//爲小數時
if(exp <= 0) return 0;
return exp<<23;
}
3 實驗結果
完成實驗後,在實驗目錄下輸入 ./driver.pl 命令,會得到以下結果。