bit-manipulation Java:对负数进行右移




1 Answers

运算符>>调用右移位 ,将所有位向右移位指定的次数。 重要的是>>将最左边的符号位(最高有效位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

注意:最左边的三个位是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

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

所以这就是运算符>> 签名右移 ,保留左操作数的符号。

[你的答案]
在你的代码中,你使用>>运算符将-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(图形编程)中很有用,虽然我没有使用它但是在过去的某些地方读过它。

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

编辑

关于无符号右移运算符>>>运算符的一些有趣之处。

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

  • >><< ,operator >>>运算符也从不抛出异常。

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

  • >>>运算符可以对其操作数执行类型转换; 与算术二元运算符不同,每个操作数都是独立转换的。 如果操作数的类型是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))
    
  • 如果左操作数的类型很长,则只使用右操作数值的六个最低有效位作为移位距离。( 即2 5 = 64位=长位数

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

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

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

java bit-manipulation bitwise-operators bit-shift negative-number

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

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

结果是:

11111111111111111111111111110001
11111111111111111111111111111111

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




Related