我理解无符号右移运算符">>>"在Java中,但为什么我们需要它,为什么我们不需要相应的无符号左移运算符?
答案 0 :(得分:26)
>>>
运算符允许您将int
和long
视为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;
如果整数high
和low
接近最大的机器整数,则上述内容将是正确的但
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
答案 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))));