Java:对负数进行右移

Cac*_*ing 24 java bit-manipulation bit-shift bitwise-operators negative-number

关于负数的右移操作我很困惑,这里是代码.

int n = -15;
System.out.println(Integer.toBinaryString(n));
int mask = n >> 31;
System.out.println(Integer.toBinaryString(mask));
Run Code Online (Sandbox Code Playgroud)

结果是:

11111111111111111111111111110001
11111111111111111111111111111111
Run Code Online (Sandbox Code Playgroud)

为什么要将负数移31而不是1(符号位)?

Alv*_*ong 36

因为在Java中没有无符号数据类型,所以有两种类型的右移:算术移位 >>逻辑移位 >>>.http://docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html

算术移位>>将保持符号位.
算术转移

无符号移位>>>不会保持符号位(因此填充0s).
逻辑转变

(图片来自维基百科)


顺便说一下,算术左移和逻辑左移都具有相同的结果,因此只有一个左移<<.

  • 我的意思是,是*`顺便说一下,算术移位和逻辑移位都有相同的结果,所以左移只有一个<<`*真的如此? (4认同)

Gri*_*han 14

操作员>>调用Signed右移,将所有位向右移动指定的次数.重要的是>> 将最左边的符号位(最高有效位MSB)填充到移位后最左边的位.这称为符号扩展,用于在向右移动时保留负数的符号.

下面是我的图表表示,其中的示例显示了它的工作原理(对于一个字节):

例:

i = -5 >> 3;  shift bits right three time 
Run Code Online (Sandbox Code Playgroud)

五分之二的补充形式是 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  
Run Code Online (Sandbox Code Playgroud)

以下是,如何>>运作?当你这样做-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
Run Code Online (Sandbox Code Playgroud)

注意:最左边的三位是1,因为每个移位符号位都被保留,每个位也是正确的.我写过这个符号是传播的,因为所有这三个位都是因为符号(而不是数据).

另外由于三个右移,最右边三个位都输了.

右两个箭头之间的位从先前的位中暴露出来-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
Run Code Online (Sandbox Code Playgroud)

再看看我写的符号是传播的,所以最左边的三个零是由于符号位.

所以这是操作符>> 签名右移,保留左操作数的符号.

[你的答案]
在你的代码中,你使用运算符-15向右移动了一段31时间,>>因此最右边的31位被释放,结果是所有位1实际上-1都是大小.

您是否注意到这种方式 -1 >> n相当于不是声明.
我相信如果i = -1 >> n有人应该i = -1通过Java编译器进行优化,但这是另一回事

接下来,有趣的是,在Java中可以看到另一个右移位运算符可用,>>>称为无符号右移.并且它在逻辑上有效,并且每次换档操作从左侧填充零.因此,如果>>>对正数和正数使用无符号右移运算符,则在每个右移位置总是在最左侧位置获得零位.

例:

i = -5 >>> 3;  Unsigned shift bits right three time 
Run Code Online (Sandbox Code Playgroud)

以下是我的图表,演示了表达式的-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  
Run Code Online (Sandbox Code Playgroud)

你可以注意到:这次我没有写出传播的符号位,但实际上>>>操作符插入零.因此>>>,不保留符号而是进行逻辑右移.

根据我的知识,无符号右移在VDU(图形编程)中很有用,虽然我没有使用它但是在过去的某些地方读过它.

我建议你读一下:>>>和>>之间的区别:>>是算术右移,>>>是逻辑右移.

编辑:

关于无符号右移算子算>>>子的一些有趣的.

  • 无符号右移运算符>>>产生一个纯值,即左操作数右移,零0扩展由右操作数指定的位数.

  • 喜欢>><<,运算符>>>也运算符永远不会抛出异常.

  • 无符号右移运算符的每个操作数的类型必须是整数数据类型,否则会发生编译时错误.

  • >>>操作者可在其操作数执行类型转换; 与算术二元运算符不同,每个操作数都是独立转换的.如果操作数的类型是byte,short或char,则在计算运算符的值之前将该操作数转换为int.

  • 无符号右移运算符生成的值的类型是其左操作数的类型. LEFT_OPERAND >>> RHIGT_OPERAND

  • 如果左操作数的转换类型是int,则只使用右操作数值的五个最低有效位作为移位距离.(即2 5 = 32位= int中的位数) 因此,移位距离在0到31的范围内.

    这里,产生的值r >>> s与以下相同:

    s==0 ? r : (r >> s) & ~(-1<<(32-s))
    
    Run Code Online (Sandbox Code Playgroud)
  • 如果左操作数的类型很长,则只使用右操作数值的六个最低有效位作为移位距离.(即2 5 = 64位=长位数)

    这里,产生的值r >>> s与以下相同:

    s==0 ? r : (r >> s) & ~(-1<<(64-s))
    
    Run Code Online (Sandbox Code Playgroud)

一个有趣的参考: [第4章] 4.7移位运算符