>>> 和 >> 的区别

466

在Java中,>>>>>运算符有什么区别?


9个回答

510

>> 是算术右移,>>> 是逻辑右移。

算术右移会将符号位扩展以保留数字的有符号性。

例如:用8位表示的-2是 11111110(因为最高位具有负权值)。使用算术右移将其向右移动一个位会得到11111111或-1。 然而,逻辑右移并不关心该值可能代表的是带符号的数字;它只是将所有内容向右移动,然后从左边填充0。 使用逻辑右移将我们的-2向右移动一个位会得到01111111


13
尽管我同意并感激算术移位可以用来将有符号数乘以 2^k,但我觉得奇怪的是这是每个人的答案。一串比特不是一个数字,而且 >> 可以用在任何一串比特上:无论该比特串扮演什么角色,也无论它是否具有“符号”的概念,它始终执行相同的操作。如果将您已经很好的答案扩展到讨论操作数 被解释为有符号数的情况,那会怎样?我的抱怨有道理吗? - Ziggy
14
为什么你认为一个比特串不是数字?你会说一串十进制数字不是数字吗? - danben
6
讨论一个东西是否是数字只有在将其与特定情境联系起来时才有意义。如果互联网只是电力,那么我同意字符串就是数字。 - bvdb
1
@danben 但实际上,我认为Ziggy真正指的是(在我看来),String也可以视为char[]。他并没有说char不是数字;他只是说它是无符号数字。我认为那就是他迷失的地方。 - bvdb
12
@Ziggy是正确的:并不是每个比特串都是数字,也不是每个十进制数字序列都是数字。例如:电话号码、邮政编码(在许多国家)等是十进制数字串,但对它们进行加、减或乘并没有意义,因此它们并不是真正的数字。它们恰好是十进制数字串,但应该被视为字符串。(加拿大和英国的邮政编码包含字母和数字。) - jcsahnwaldt Reinstate Monica
显示剩余3条评论

119

>>>代表无符号右移,它会插入0。>>代表带符号右移,它会扩展符号位。

JLS 15.19 移位操作符

移位操作符包括左移操作符 <<,带符号右移操作符 >> 和无符号右移操作符 >>>

n>>s 的值是 n 向右移动 s 位,并且使用符号扩展

n>>>s 的值是 n 向右移动 s 位,并且使用零扩展

    System.out.println(Integer.toBinaryString(-1));
    // prints "11111111111111111111111111111111"
    System.out.println(Integer.toBinaryString(-1 >> 16));
    // prints "11111111111111111111111111111111"
    System.out.println(Integer.toBinaryString(-1 >>> 16));
    // prints "1111111111111111"
为了更清晰地表达,添加正面对应项。
System.out.println(Integer.toBinaryString(121));
// prints "1111001"
System.out.println(Integer.toBinaryString(121 >> 1));
// prints "111100"
System.out.println(Integer.toBinaryString(121 >>> 1));
// prints "111100"

由于它是正数,因此有符号和无符号的移位将在最左边的位上添加0。

相关问题


没有你的例子,我就无法理解。 - mr5

55

>>>始终将0放在最左边的位,而>>将根据其符号将1或0放在左侧。


54

它们都是右移操作,但是>>>无符号的。

根据文档

无符号右移位运算符 ">>>" 在最左边位置填充0,而带符号右移位运算符 ">>" 在最左边位置的填充方式取决于符号扩展。


14
可以举个例子来说明吗? - Kasun Siyambalapitiya
1
我也认为你应该举个例子。 - byxor
我猜 >>> 是无符号的,但为什么 7>>32=7?我运行了一个循环,每次进行一次移位操作,并发现在经过 32 次移位后,它又回到了 7。唯一有意义的解释是,对于每个移出的数字,它都进入了一个“外圆”。经过 32 次移位后,它以某种方式回到了原来的位置,但显然这仍然没有意义。到底发生了什么? - Ian L
@IanLimarta 不行吗?我只得到了0。(for (int i = 7 << 1, j = 0; j < 32; j++) System.out.println(Integer.toString(i >>= 1, 2));)如果你的意思是为什么 >>32 返回原始值,可以参考这里 - Salem
对不起,我的意思是为什么 '7>>>32=7'。 - Ian L
@IanLimarta 当我对此进行了一些测试,发现当使用逻辑右移 ">>>" 时,如果您将正整数向右移动,则结果仍将是正整数,因此其行为与算术右移 ">>" 没有任何不同。 如果您在负数上使用逻辑右移 ">>>",那就会产生差异,因为带入的最左边位是零。 然而,对于您提出的问题示例,执行逻辑右移 32 位将返回您要尝试移位的相同起始值。 - Hoonerbean

46

逻辑右移 (v >>> n) 返回一个值,其中 v 中的位已经向右移动了 n 位,并且从左侧填充了0。考虑将二进制写成8位值进行移位:

01111111 >>> 2 = 00011111
10000000 >>> 2 = 00100000
如果我们将比特解释为无符号非负整数,逻辑右移的效果是将该数字除以相应的2的幂。然而,如果数字采用二进制补码表示,则逻辑右移不会正确地将负数除以2的幂。例如,在Java中通常采用二进制补码解释位时,上面第二次右移将128向右移动32位。但是当数字为-128时,则向右移32位。
因此,如果您要进行移位以便除以2的幂,则需要使用算术右移(v >> n)。它返回一个值,其中v中的位已向右移动了n位,并且从左侧复制v的最左位
01111111 >> 2 = 00011111
10000000 >> 2 = 11100000

当位数以二进制补码表示时,算术右移的作用相当于除以2的某个幂。这是因为最左边的位是符号位。除以2的某个幂必须保持符号不变。


15

了解更多关于位运算和位移操作符的内容。

>>      Signed right shift
>>>     Unsigned right shift

位模式由左操作数给出,右操作数指定移动的位数。无符号右移运算符>>>将一个移入最左侧位置,

>>在移位后的最左侧位置取决于符号扩展。

简单来说,>>>总是将一个移入最左侧位置,而>>根据数字的符号进行移位,即负数为1,正数为0。


例如使用负数和正数尝试一下。

int c = -153;
System.out.printf("%32s%n",Integer.toBinaryString(c >>= 2));
System.out.printf("%32s%n",Integer.toBinaryString(c <<= 2));
System.out.printf("%32s%n",Integer.toBinaryString(c >>>= 2));
System.out.println(Integer.toBinaryString(c <<= 2));

System.out.println();

c = 153;
System.out.printf("%32s%n",Integer.toBinaryString(c >>= 2));
System.out.printf("%32s%n",Integer.toBinaryString(c <<= 2));
System.out.printf("%32s%n",Integer.toBinaryString(c >>>= 2));
System.out.printf("%32s%n",Integer.toBinaryString(c <<= 2));

输出:

11111111111111111111111111011001
11111111111111111111111101100100
  111111111111111111111111011001
11111111111111111111111101100100

                          100110
                        10011000
                          100110
                        10011000

谢谢。只想添加一个注释,以引用有关Integer.MAX_VALUE,Integer.MIN_VALUE,-1,0,1的位表示。例如:System.out.println(Integer.MAX_VALUE + ": " + String.format("%32s", Integer.toBinaryString(Integer.MAX_VALUE)).replace(' ', '0')); Integer.MAX_VALUE01111111111111111111111111111111; Integer.MIN_VALUE10000000000000000000000000000000; -111111111111111111111111111111111; 000000000000000000000000000000000; 100000000000000000000000000000001 - Andy Dong

7

右移逻辑运算符(>>> N)将位向右移动N个位置,舍弃符号位并用0填充N个最左边的位。例如:

-1 (in 32-bit): 11111111111111111111111111111111

执行 >>> 1 操作后的结果为:

2147483647: 01111111111111111111111111111111

右移算术运算符(>> N)将位向右移动N个位置,但保留符号位并用1填充N个左侧最高位。例如:
-2 (in 32-bit): 11111111111111111111111111111110

执行 >> 1 操作后,结果如下:

-1: 11111111111111111111111111111111

2
>>  Signed right shift 
>>> Unsigned right shift

例子:

byte x, y;  x=10;  y=-10;  
SOP("Bitwise Left Shift: x<<2 = "+(x<<2));  
SOP("Bitwise Right Shift: x>>2 = "+(x>>2));  
SOP("Bitwise Zero Fill Right Shift: x>>>2 = "+(x>>>2));  
SOP("Bitwise Zero Fill Right Shift: y>>>2 = "+(y>>>2));

输出结果将是:-
Bitwise Left Shift: x<<2 = 40
Bitwise Right Shift: x>>2 = 2
Bitwise Zero Fill Right Shift: x>>>2 = 2
Bitwise Zero Fill Right Shift: y>>>2 = 1073741821

-2

>>(signed) 对于 8 >> 2 和 -8 >> 2 会得到不同的结果。

对 8 进行右移

8 = 1000(二进制表示)

进行 2 位右移

8 >> 2:

1000 >> 2 = 0010(相当于 2)

对 -8 进行右移

8 = 1000(二进制表示)

1 的补码 = 0111

2 的补码:

0111 + 1 = 1000

符号位为 1

在补码结果上进行 2 位右移

-8 >> 2:

1000 >> 2 = 1110(相当于 -2)


>>(unsigned) 对于 8 >>> 2,-8 >>> 2 将给出相同的结果。

8 的无符号右移

8 = 1000

8 >>> 2 = 0010

-8 的无符号右移

-8 = 1000

-8 >>> 2 = 0010


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接