无符号右移运算符“>>>”的目的是什么?在Java?

时间:2013-05-26 21:39:42

标签: java programming-languages bit-manipulation

我理解无符号右移运算符">>>"在Java中,但为什么我们需要它,为什么我们不需要相应的无符号左移运算符?

6 个答案:

答案 0 :(得分:26)

>>>运算符允许您将intlong视为32位和64位无符号整数类型,这些类型在Java语言中是缺失的。

当您移动不代表数值的内容时,这非常有用。例如,您可以使用32位int来表示黑白位图图像,其中每个int在屏幕上编码32个像素。如果您需要向右滚动图像,您希望int左侧的位变为零,以便您可以轻松地从相邻的int s中放置位:

 int shiftBy = 3;
 int[] imageRow = ...
 int shiftCarry = 0;
 // The last shiftBy bits are set to 1, the remaining ones are zero
 int mask = (1 << shiftBy)-1;
 for (int i = 0 ; i != imageRow.length ; i++) {
     // Cut out the shiftBits bits on the right
     int nextCarry = imageRow & mask;
     // Do the shift, and move in the carry into the freed upper bits
     imageRow[i] = (imageRow[i] >>> shiftBy) | (carry << (32-shiftBy));
     // Prepare the carry for the next iteration of the loop
     carry = nextCarry;
 }

上面的代码没有注意高三位的内容,因为>>>运算符使它们成为

没有相应的<<运算符,因为对有符号和无符号数据类型的左移操作是相同的。

答案 1 :(得分:13)

>>>也是 找到两个(大)整数的舍入均值的安全有效的方法:

int mid = (low + high) >>> 1;

如果整数highlow接近最大的机器整数,则上述内容将是正确的但

int mid = (low + high) / 2;
由于溢出,

可能会得到错误的结果。

这是一个example use,修复了一个天真的二进制搜索中的错误。

答案 2 :(得分:3)

基本上这与符号(数字移位)或无符号移位(通常是像素相关的东西)有关。

由于左移,无论如何都不处理符号位,它是一样的(&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&...

无论哪种方式,我还没有遇到任何需要使用&gt;&gt;&gt;的人,但我确信他们在那里做着惊人的事情。

  

如您所见,&gt;&gt;操作员自动填写   每次发生移位时,具有其先前内容的高位。   这保留了价值的标志。但是,有时这是   不可取的。例如,如果你正在改变那些没有的东西   表示数字值,您可能不希望使用符号扩展名   地点。当您使用基于像素的情况时,这种情况很常见   价值观和图形。在这些情况下,您通常会想要换班   无论初始值是多少,都归零到高位。   这称为无符号移位。为此,您将使用   java的无符号,右移运算符,&gt;&gt;&gt;,它总是移位零   进入高阶位。

进一步阅读:

http://henkelmann.eu/2011/02/01/java_the_unsigned_right_shift_operator

http://www.java-samples.com/showtutorial.php?tutorialid=60

答案 3 :(得分:3)

如果一个int表示一个数字,并且一个希望将其除以2的幂,向负无穷大四舍五入,则有符号右移运算符很有用。在做缩放坐标以进行显示时,这可能很好;它不仅比分割快,而且在缩放之前因比例因子而不同的坐标之后将相差一个像素。如果不是使用移位而是使用除法,那将无效。当按比例缩放2倍时,例如,-1和+1相差2,因此应该在之后相差1,但-1 / 2 = 0且1/2 = 0。如果相反,使用带符号的右移,事情很顺利:-1&gt;&gt; 1 = -1和1&gt;&gt; 1 = 0,正确地产生相隔一个像素的值。

无论是输入预期只有一位设置还是希望结果也是如此,或者在使用循环输出所有位的情况下,无符号运算符都很有用。一句话,希望它干净地终止。例如:

void processBitsLsbFirst(int n, BitProcessor whatever)
{
  while(n != 0)
  {
    whatever.processBit(n & 1);
    n >>>= 1;
  }
}

如果代码使用带符号的右移操作并传递了负值,它将无限输出1。然而,使用无符号右移运算符,最重要的位最终将被解释为与其他任何位一样。

当计算在算术上产生0到4,294,967,295之间的正数并且希望将该数除以2的幂时,无符号右移算子也可能是有用的。例如,当计算已知为正的两个int值的总和时,可以使用(n1+n2)>>>1而不必将操作数提升为long。此外,如果希望在不使用浮点数学的情况下将正int值除以pi之类的值,则可以计算((value*5468522205L) >>> 34) [(1L <&lt; 34)/ pi为5468522204.61,其中四舍五入产量5468522205]。对于超过1686629712的股息,​​value*5468522205L的计算将产生“负”值,但由于已知算术正确的值为正,因此使用无符号右移将允许使用正确的正数。

答案 4 :(得分:1)

负数的正常右移>>将使其保持负数。即符号位将被保留。

无符号右移>>>也会移位符号位,将其替换为零位。

没有必要具有等效的左移,因为只有一个符号位,它是最左边的位,所以它只在右移时干扰。

基本上,不同之处在于保留符号位,其他用零替换符号位。

对于正数,他们的行为相同。

有关同时使用>>>>>的示例,请参阅BigInteger shiftRight

答案 5 :(得分:0)

在Java域中,大多数典型应用程序避免溢出的方法是使用强制转换或Big Integer,例如前面示例中的int to long。

int hiint = 2147483647;
System.out.println("mean hiint+hiint/2 = " + ( (((long)hiint+(long)hiint)))/2);
System.out.println("mean hiint*2/2 = " + ( (((long)hiint*(long)2)))/2);

BigInteger bhiint = BigInteger.valueOf(2147483647);
System.out.println("mean bhiint+bhiint/2 = " + (bhiint.add(bhiint).divide(BigInteger.valueOf(2))));