首先,直接上題目:
根據X得到F和G,其中X、F、G均是有符號的32位整型數,其中F = X/2; G = X>>1; 發現 F != G,下面的說法哪個是正確的:
A 編譯錯誤 B X是奇數 C X是負數 D F-G=1
上述4個選項中,首先排除A和B,顯然隨便舉個反例就有了。
對於C,這裏就涉及到負數在計算機中的表示形式了,至於怎麼個表示法,下面一一道來:
對於負數,在計算機內的表示方法是怎麼樣的呢?
下面的代碼可以說明一切:
void print(int x)
{
//這裏將形參的int轉化爲unsigned int,是爲了說明負數的補碼錶示方法而已。
unsigned int tmp = x;
cout << tmp << endl;
string s;
while(tmp)
{
if(tmp & 1) s.push_back('1');
else s.push_back('0');
tmp >>=1;
}
reverse(s.begin(),s.end());
cout << s << endl;
}
上述代碼的執行結果, x = 9 時,執行結果爲: 1111 1111 1111 1111 1111 1111 1111 0111
這裏的補碼的表示其實很簡單,轉化過程無非是原碼,反碼和補碼的順序而已:
原碼: 1 000 0000 0000 0000 0000 0000 0000 1001 //最高位是符號位,後面的31位是數字位
反碼: 1 111 1111 1111 1111 1111 1111 1111 0110 //除了符號位,其他爲全部變反
補碼: 1 111 1111 1111 1111 1111 1111 1111 0111 //反碼加1即可
這樣的話,對於上述的代碼的結果解析就這樣了,現在執行 :
F = X/2 = -9/2 = -4 ; // 這就是除法運算
G = X>>1 = (-9) >> 1 就是將上述的補碼部分向右移一位,執行過稱爲:
1 111 1111 1111 1111 1111 1111 1111 0111
1 1 111 1111 1111 1111 1111 1111 1111 0111 //去掉最右邊的藍色的1,加上最左邊的綠色的1
於是乎,上述結果變爲:
1 1 111 1111 1111 1111 1111 1111 1111 011 //這裏是結果的補碼,現在講結果的補碼轉換爲源碼,從而得到原來的數值。其過程爲:
1 111 1111 1111 1111 1111 1111 1111 1011 //補碼
1 111 1111 1111 1111 1111 1111 1111 1010 //補碼減去1 變爲反碼
1000 0000 0000 0000 0000 0000 0000 0101 //除了最高位的符號位,其他爲變反,
結果竟然是-5!!!!
也就是說 (-9 >> 1) = -5 !!!!
也就是說出現了上述的 F != G, F-G = 1 。於是答案是D.