21

對負數右移操作我很困惑,這裏是代碼。Java:在負數上右移

int n = -15; 
System.out.println(Integer.toBinaryString(n)); 
int mask = n >> 31; 
System.out.println(Integer.toBinaryString(mask)); 

,其結果是:

11111111111111111111111111110001 
11111111111111111111111111111111 

爲什麼右移31不爲1(符號位)移位一個負數?

+2

順便說一句,你可以使用'>>> -1',它可以用於'int'和'long'類型。 – 2013-03-17 05:48:19

回答

30

因爲在Java中沒有無符號數據類型,所以有兩種類型的右移:arithmetic shift>>logical shift>>>http://docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html

算術移位>>將保持符號位。
Arithmetic shift

無符號移位>>>不會保留符號位(從而填充0多個)。
Logical shift

(維基百科圖像)


順便說,既算術左移和邏輯左移具有相同的結果,所以僅存在一個左移<<

+0

如果你這樣做,會發生什麼**'10101010 << 1' **? **'11010100' ** **或'01010100' **? – 2013-04-16 23:59:55

+0

@AurélienOoms這是一個左移,填補'右側0's。 – 2013-04-17 02:01:57

+1

我的意思是,是*'順便說一句,無論是算術移位和邏輯移位有同樣的結果,所以只有一個左移<<'*真的如此嗎? – 2013-04-17 02:32:52

12

運算符>>調用帶符號右移,將所有位右移指定的次數。重要的是>>填充最左邊的符號位(最高有效位MSB)到最後一位。這稱爲符號擴展名服務當您將它們右移時保留負數的符號

下面是我用一個例子圖示來說明其工作原理(一個字節):

例子:

i = -5 >> 3; shift bits right three time 

五位二進制補碼形式爲1111 1011

記憶表徵:

MSB 
+----+----+----+---+---+---+---+---+ 
| 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 
+----+----+----+---+---+---+---+---+ 
    7 6 5 4 3 2 1 0 
^This seventh, the left most bit is SIGN bit 

而且下面是,>>如何工作?當你做-5 >> 3

     this 3 bits are shifted 
         out and loss 
MSB     (___________)  
+----+----+----+---+---+---+---+---+ 
| 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 
+----+----+----+---+---+---+---+---+ 
    | \     \ 
    | ------------|  ----------| 
    |    |    | 
    ▼    ▼    ▼ 
+----+----+----+---+---+---+---+---+ 
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 
+----+----+----+---+---+---+---+---+ 
(______________) 
The sign is   
propagated 

注意:最左邊的三位是一個因爲每個班次符號位是保留的,每個位是正確的了。我寫了該符號傳播,因爲所有這三位都是由於符號(但不是數據)。

也因爲三個右移最右邊的三位都是虧損的。

右兩個箭頭之間的位從前面的位-5中暴露出來。

我認爲如果我也爲一個正數編寫一個例子會很好。下面的例子是5 >> 3五是一個字節是0000 0101

     this 3 bits are shifted 
         out and loss 
MSB     (___________)  
+----+----+----+---+---+---+---+---+ 
| 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 
+----+----+----+---+---+---+---+---+ 
    | \     \ 
    | ------------|  ----------| 
    |    |    | 
    ▼    ▼    ▼ 
+----+----+----+---+---+---+---+---+ 
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 
+----+----+----+---+---+---+---+---+ 
(______________) 
The sign is   
propagated 

再次看到我寫符號傳播,所以最左邊的三個零是由於籤位。

所以這就是運算符>>簽名右移做,保留左操作數的符號。

[答案]
在代碼中,你換班-15到適合使用>>操作讓你最右31位鬆動31次,結果是所有位1實際-1在量值。

你注意到了嗎,這樣-1 >> n就相當於沒有聲明。
我相信,如果一個做i = -1 >> n應該被Java編譯器進行優化,以i = -1,但那是另一回事

下,這將是有趣的Java的瞭解多了一個向右移位運算符可用>>>稱爲無符號右移。它在邏輯上起作用,並且在每次換班時從左側填充零。因此,在每次右移時,如果您使用無符號右移>>>運算符來計算負數和正數,則始終在最左邊的位置得到一個零位。

例子:

i = -5 >>> 3; Unsigned shift bits right three time 

,下面將我的圖表,演示瞭如何表達-5 >>> 3作品?

     this 3 bits are shifted 
         out and loss 
MSB     (___________)  
+----+----+----+---+---+---+---+---+ 
| 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 
+----+----+----+---+---+---+---+---+ 
    | \     \ 
    | ------------|  ----------| 
    |    |    | 
    ▼    ▼    ▼ 
+----+----+----+---+---+---+---+---+ 
| 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 
+----+----+----+---+---+---+---+---+ 
(______________) 
    These zeros 
    are inserted 

你可以注意到:這次我不寫那個傳播符號位,但實際上>>>操作插入零。因此>>>不保留符號,而是做邏輯右移。

在我的知識中,未經簽名的右移在VDU(圖形編程)中很有用,雖然我沒有使用它,但是在過去的某些地方讀過它。

我建議你讀這個:Difference between >>> and >>>>是算術右移,>>>是邏輯右移。

編輯

一些有趣的無符號右移運算符>>>運營商。

  • 無符號的向右移位運算>>>產生一個純值,該值是它的左操作數由它的右操作數中指定的比特數右移用零0擴展。

  • >><<一樣,運算符>>>也是運算符從不拋出異常。

  • 無符號右移運算符的每個操作數的類型必須是整數數據類型,否則會發生編譯時錯誤。

  • 運算符>>>可以對其操作數執行類型轉換;與算術二元運算符不同,每個操作數都是獨立轉換的。如果操作數的類型是byte,short或char,那麼在計算運算符的值之前,該操作數將轉換爲int。

  • 無符號右移運算符產生的值的類型是其左操作數的類型。LEFT_OPERAND >>> RHIGT_OPERAND

  • 如果轉換類型的左操作數的是int,則右操作數的值僅五個最低顯著位用作移位距離。 (即2 = 32位=位在INT數)
    所以,移位距離的範圍是從0至31

    在此,通過r >>> s產生的值是相同的:

    s==0 ? r : (r >> s) & ~(-1<<(32-s)) 
    
  • 如果左操作數的類型是長,則只有六個最右邊的操作數的值的顯著位用作移位距離。(即2 = 64位=長的位數

    在此,通過r >>> s產生的值是相同的,如下所示:

    s==0 ? r : (r >> s) & ~(-1<<(64-s)) 
    

甲有趣參考:[Chapter 4] 4.7 Shift Operators

+0

它並不是真的'放1',它只是保留了符號位,不管它是什麼。 – EJP 2013-03-17 05:43:26

+1

一個更簡單的答案是更正確和更多的幫助。操作員不會查看操作數是負數還是負數,然後執行兩個不同的操作。 – EJP 2013-03-17 05:50:50

+0

請堅持這一點,並保持個性。你的解釋是必要的兩倍,並根據你的評論來判斷@AlvinWong的答案,你仍然不明白爲什麼。 – EJP 2013-03-17 05:58:40

3

因爲>>被定義爲一個算術右移,這保留了標誌。爲了達到預期的效果,請使用邏輯右移,即>>>運算符。

+0

好什麼,我想說,你用一個詞來寫*'保留好的符號。 – 2013-03-17 06:34:16