移位運算 and 原碼、反碼、補碼
文章目錄
背景
在看《Absolute C++》時遇到的。判斷以下程式碼的輸出內容:
int i=1;
while (i<<=10)
{
cout << i << endl;
i += 3;
}
上面while判別式中i<<=10
可不是小於或遠小於的大小關係比較,而是移位運算的表示式,相當於i = i << 10
。那麼結果如何呢?
- C++中賦值是一種表示式,該表示式的返回值為所賦的值
- 那也就是看上面的程式碼中,“先左移10位,再加十進位制3”這一對操作,會不會有某一次使左移之後的值為0
什麼是移位運算,如何做
各種變數在計算機中都是以二進位制的形式存在,比如十進位制1就是10,移位
運算就是直接操作該變數的二進位制數,二進位制又有“原碼、反碼、補碼”(看這篇筆記二進位制:原碼反碼與補碼),移位
運算的操作物件是補碼
。
移位的分類,根據移位方向不同,分為:
- 左移位
<<
:符號位不參與移動,把二進位制補碼整體向左移動
多少位- 無論正數還是負數,向左移動之後右邊空出來的位,用0補
- 右移位
>>
:符號位不參與移動,二進位制補碼向右移動
多少位- 向右移動之後左邊與符號位之間空出來的位,用符號位補
- 正數的話,符號位為0,用0補
- 負數的話,符號位為1,用1補
- 向右移動之後左邊與符號位之間空出來的位,用符號位補
int型變數在64位機器中佔多少個二進位制位
其實這一塊主要是答疑:十進位制1的二進位制10,那左移2位之後為啥不是二進位制00、十進位制0,而是變成了十進位制4.
其實答案就是,十進位制1的二進位制10,並不是只佔兩個二進位制位,在10兩位的左側,還有很多個二進位制位。多少個呢:
int型變數一般長度為4個位元組,每個位元組為8個二進位制位,那麼總長也就是4*8=32位。
所以只要左移不超過32-2=30位,就不會移出被丟棄。
移位前後數值的大小關係
從二進位制到十進位制的轉換可以瞭解其關係:
二進位制:0 0 1 1 0 1 0
十進位制:$ 2^4 + 2^3 + 2^1$
如果左移1位:
二進位制:0 1 1 0 1 0 0 十進位制:$ 2^5+2^4+2^2=2*(2^4 + 2^3 + 2^1)$
結論:
-
左移的時候,如果沒有移出左邊界,則 結 果 = 原 數 ∗ 2 移 動 的 位 數 結果 = 原數 * 2^{移動的位數} 結果=原數∗2移動的位數
- 怎麼判斷有沒有移出呢?該數原來的二進位制數最左側的1在第幾位 and 該型別的所佔位數
-
右移的時候,如果沒有移出左邊界,則 結 果 = 原 數 / 2 移 動 的 位 數 結果 = 原數 / 2^{移動的位數} 結果=原數/2移動的位數
回到文章開頭的題目
int i=1;
while (i<<=10)
{
cout << i << endl;
i += 3;
}
十進位制1與十進位制3的原碼與補碼:
原 碼 補 碼
1 0000 0000 ... 0000 0001 0111 1111 ... 1111 1111
3 0000 0000 ... 0000 0011 0111 1111 ... 1111 1101
----------------------- -----------------------
共32位 共32位
0 0000 0000 ... 0000 0000 0000 0000 ... 0000 0000
注意int型,32位,可表示範圍為[2^32/2, 2^32/2=214 748 364 8)
首先,對補碼進行左移位操作,每次左移10位,移位之後右邊的空位補0;
其次,while判別式中實際上是一個表示式 i = i << 10
↓
那也就是判斷,每次左移10位再加十進位制3,會不會有一次遇到i=0
的情況:
- 第一次判斷時,
i
=
1
∗
2
10
=
1024
i=1*2^{10}=1024
i=1∗210=1024,非0,進入while
- +3, i = 2 10 + 3 = 1027 i=2^{10}+3=1027 i=210+3=1027
- 第二次判斷時,
i
=
1027
∗
2
10
=
1051648
i=1027*2^{10}=1051648
i=1027∗210=1051648,非0,進入while
- +3, i = 1051648 + 3 = 1051651 i=1051648+3=1051651 i=1051648+3=1051651
- 第三次判斷時,
i
=
1051651
∗
2
10
=
1076890624
i=1051651*2^{10}=1076890624
i=1051651∗210=1076890624,非0, 且沒有超出右邊界,進入while
- +3, i = 1076890624 + 3 = 1027890627 i=1076890624+3=1027890627 i=1076890624+3=1027890627
- 第4次及之後判斷時,$i_{n-1}*1024 > 右邊界,輸出結果不確定性
這樣二進位制與十進位制轉換,太麻煩了,如果只是判斷while迴圈會不會停止的話,可以僅分析二進位制。0的二進位制各位均為0,只要看某次+3(二進位制再左移10位後是否各位均為0即可:
- 十進位制1的二進位制,僅最右側有1個1,左移10位後,右邊10位均為0;
- 加十進位制3後,看上面3的補碼,右邊10位有9個1,所相加之後右10位與3的補碼相同,含有1
- 進入while判別式,再左移10位,然後再加3,右邊的9個1一直無法移出去,也就是說始終無法達到全0,即十進位制0,所以while無限迴圈。