標籤:深入理解電腦系統 2-66 c
最近打算把《深入理解電腦系統》再讀一遍,說實話這本書讀多少遍都不嫌多,每讀一遍都會有收穫。這次決心把書中的習題整個過一遍,並把其中我認為比較典型的、有意思的寫城博文記錄一下,恩,這就是這篇博文的由來。懇請各路大神拍磚。
一. 問題描述(鑒於我這不忍直視的翻譯水平,我就直接貼書中的問題描述了):
Generate mask indicating leftmost 1 in x. Assume w = 32.
For example 0xFF00 -> 0x8000, and 0x6600 --> 0x4000.
If x = 0, then return 0.
int leftmost_one(unsigned int x);
二. 結果正確但不符合題意的解決方案:
剛開始看到這個問題,想了想,突然間有了一個很簡單的解決方案,所以趕緊寫代碼試了一下,恩,效果不錯,所得結果是正確的。(竊喜),但再仔細看題目要求,這和說好的不一樣啊!!帖代碼:
int leftmost_one(unsigned int x){unsigned int base = 0x80000000;while(base){if((x & base))break;base >>= 1;}}
意思很簡單,既然題目中假設w=32,那麼我想,只需要從32位下最大的數base開始和x進行與運算,如果結果不為零,那麼這個base就是x中最左邊的那個1所表示的數了。
三. 分析:
題目的要求是,讓我們產生一個掩碼,用來標識出x中最左邊的那個1。(換句話說是讓我們找到一個掩碼,使得x除了最左邊為1的那一位,別的位都置為0),很遺憾我們上面的代碼並沒有產生任何叫掩碼的東西。以下來分析一下這個問題:
書中題目下方有個小提示,“把x轉換成形如 000...111..的形式”,好吧,竟然是這麼含蓄的提示。
假設此時的字長w = 8,假設 x = 00010110,那麼結果必然為 0001 0000,什麼樣的掩碼能達到這個效果呢,我們想到了這個mask = xxx1 0000,(x 既可以為0,也可以為1)
那麼 x & mask = 0001 0110 & xxx1 0000 = 0001 0000。現在問題的關鍵就是怎麼才能由x產生這個掩碼mask:(我們這時要想一想那個含蓄的提示了)
在x中最左邊的1左邊的位全為0或者沒有,那麼我們可以通過位元運算把最左邊的1右邊的所有位都置為1(好拗口),如下:
0001 1111
然後在此基礎上取反,有:1110 0000,然後再右移一位,有 0111 0000,哈哈,此時我們的掩碼就產生了。帖代碼:
int leftmost_one(unsigned int x){unsigned int mask = x;mask |= mask >> 1;mask |= mask >> 2;mask |= mask >> 4;mask |= mask >> 8;mask |= mask >> 16;mask = (~mask) >> 1;return x & mask;}
《深入理解電腦系統》第二章習題2_66