關於移位的有意思的小問題

首先,直接上題目:

根據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  //補碼

  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.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章