CSAPP DataLab


斷斷續續做了兩天可算做的差不多,,

注意不同版本的題目可能會有所不同,搜了很多他們的題目和現在官網給的實驗題都不一樣,自己獨立思考完整做一遍順便記錄一下。

PS:剛開始這些難度為1的題有的說實話我都做了挺久的,不過到后面雖然難度上升了,但是確越做越有感覺了,另外完整做一遍感覺很有意思,這些題總體感覺就是讓你自己把那些運算符< ,> ? 什么的自己使用位級運算手動實現一遍,知道底層是怎樣運作的。

一,

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 2; }
View Code

 

題目如圖,

題目解釋:使用~ & 完成 ^ 位運算,雖然難度很低,但是我也推導了半天,,

思路:異或可以理解為取出a,b之中不相同的位,& 就是取出為都為1的位,那么我們可以先取出同為1的,然后取反,就得到了同為0或者不相同的位,即 ~(a&b) ,接着,我們取出同為0的,取反,得到同為1或者不相同的位,即~(~a&~b), 接着,再取這兩個的交集,就是我們所需要的不相同的位。即

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

tmin:返回補碼整數的最小值,補碼表示就是有個符號位,int類型shi是4個字節,32位,所以最小值就是1<<31  ,符號位為1,其他位都為0

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

isTmax:如果是補碼最大值就返回1,否則返回0,Tmax是  0x7FFFFFFF,

雖然還是一個簡單題,但是我又想了很久,而且感覺這樣子很麻煩。。

思路:核心是利用溢出。

理性分析了一下,想要返回0,1,那么肯定要用到 ! 運算符,一個常數的非是0,除了!0=1,所以,我們需要構造出來一個表達式,讓x為Tmax時候值剛好為0,其他情況值都為1,這樣子取非,就可以得到結果了。我這里想的是如果X是Tmax,那么~x就是Tmin,所以判斷~x是不是Tmin,利用溢出來判斷,給~x加上-1(~0),Tmin情況下會產生溢出,然后會進行符號截斷,Tmin-1 = Tmax,再利用Tmax+Tmin+1 = 0得到我們想要的0,再取非即可。

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

四,

allOddBits:

 

 五,

negate:輸入一個x,返回-x,

思路:第一眼看過去感覺很簡單,實際上就是很簡單,直接取反加一就行了,取反剛好就是自己的相反數-1,再加上一就可以了,不知道這個題為什么難度是2

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

 

 六,

isAsciiDigit:判斷一個數是不是在 48-57,包括57,48.剛開始沒什么思路,不過感覺肯定是要構建出來一個0或者1的在特定情況下,最后參考了一下網上的,說實話讓我自己做肯定做不出來,感覺很巧妙

思路:這個題實際上就是為了判斷兩個表達式的真假,x-48>=0  和  x-57 <= 0 ,將這兩個表達式轉換一下, 用到了第五題的結論,-48=~48+1,-57=~57+1,判斷>=0或者<=0,看符號位就可以了,符號位為1表示<0,符號位為0表示>=0,得到符號位自然是將這個32位數右移31位,

綜上,我們得到下面結論,如果 (x+~48+1)>>31  為0,那么x>=48,如果 (x+~57+1)>>31  為1 ,那么x<57,然后取前者的非,和后者進行&運算,同時滿足條件即說明x>=48,x<57。

很明顯,漏掉了邊界57,x=57時,x-57剛好為0,移位之后得到的是0,所以我們將第表達式二改為  (x+~58+1)   x為57時,結果仍為負數,符號位為1,將57這種情況成功納入到符號位為1的情況, 

* 
 * 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 !((x + (~48 + 1)) >> 31)&((x + (~58 + 1)) >> 31); }

conditional:即自己使用位級符號實現一個三目運算符

 這個題說實話沒有看懂。。

八,

isLessOrEqual(x,y)  如果y>=x  返回1,否則返回0

這個題感覺思想和前面的很像,判斷y-x>=0是否成立,即判斷y-x的符號位,如果是0的話就表明成立,1表示不成立,因為符號位1表示為負數。這樣子就簡單了,-x = ~x+1  ,符號位>>31即可得到,所以可以構造出表達式:(y+~x+1)>>31    ,要求是成立了返回1,所以再取個非就可以了。

/* 
 * isLessOrEqual - if x <= y  then return 1, else return 0 
 *   Example: isLessOrEqual(4,5) = 1.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 24
 *   Rating: 3
 */
//即使用位級運算判斷y-x>=0表達式是否成立,看符號位
int isLessOrEqual(int x, int y) {
  return !((y+(~x+1))>>31);
}

九,

logicalNeg:使用其他的位級運算符實現 ! 運算,

。。剛開始思路錯了,想着直接 x^0^1,忘記考慮了x是32位的,和0異或出來一般不會是1

思路:兩種情況,一種是! 0 = 1, 其他數  ! num = 0,所以其實只要想辦法把這兩種情況區分開來就可以了。個人感覺區分的話肯定是要找出0的特點的,很明顯,0的相反數是它本身,其他數的相反數是他的負數。利用這一點,我們可以讓x的相反數(~x+1)的符號位(>>31)和x進行異或,除了0以外結果都是1,由於不能取反,所以用if判斷一下就可以了。

int logicalNeg(int x) { if((((~x+1)>>31)^(x>>31))) return 0; return 1; }

十,

  howManyBits:返回表達x最少需要多少位

思路:感覺跟十進制轉換為2進制差不多。我想的是我們確定位數那么就需要判斷x的范圍,如果在 2^(i-1)---2^i 之間,那么就需要i位剛好可以表示,不過由於是有符號整數,所以需要再加上一位符號位,就是i+1位,所以我們只需要將logx的值向上取整,再加上1即可,這是對整數而言,對於負數來說,將負數轉換為正數進行計算,最后同樣加上一即可,至於確定x的范圍,循環除2(>>1),直到x為0為止。不過這里有兩種特殊情況,那就是Tmin和-1,Tmin由於是一個負數,如果取他的相反數進行計算的話,不存在與之對應Tmax,會導致不可預期的結果,另外-1只需要一位即可表示,+1需要兩位,這兩種特殊情況我想的是直接if判斷一下,返回相應的值,如果有更好的方法歡迎討論。

int howManyBits(int x) { int i=1; //符號位 int y=x; if(x==-1) //特殊情況 return 1; if(x==0x80000000) return 32; if(x>>31) //負數取相反數 y = ~x+1; while(y){ y = y>>1; // 除2 i++; } return i; }

。。。剩下的浮點數的題,,,,浮點數那塊看了幾次都沒看完,,等看完了再做吧!

  

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM