Java中位移(bitshifting)是如何工作的?

64
我有以下陈述:
假设字节x的位值为00101011。那么x>>2的结果是什么?
我该如何编程并有人能解释一下它是做什么的?
10个回答

110
首先,在Java中你不能对一个byte进行位移,只能对int或long进行位移。所以byte将首先进行提升,例如: 00101011 -> 00000000000000000000000000101011 或者 11010100 -> 11111111111111111111111111010100 现在,x >> N 的意思是(如果你将其视为一串二进制数字):
  • 右侧的N个比特被丢弃
  • 左侧的比特按需要重复多次以填充结果到原始大小(32或64位),例如:
00000000000000000000000000101011 >> 2 -> 00000000000000000000000000001010 11111111111111111111111111010100 >> 2 -> 11111111111111111111111111110101

1
11010100的最左边一位是1,那么它被认为是一个负数吗? - Pha3drus
@Pha3drus,是的,假设数字以二进制补码存储。请参阅https://dev59.com/6XNA5IYBdhLWcg3wNq8y。 - codewiz
我尝试在Java中使用移位操作来改变int类型的值:@Test public void testBinaryString() { int n = 4; int v = n >> 1; System.out.println("v = " + v + ", n = " + n); }但是输出结果为:v = 2, n = 4。我想知道为什么n的值没有被改变为2? - AlienOnEarth
帮忙。我试图获取一个整数的第32位,但是出现了错误行为。当我掩码该位并将其移动到第一位时,我得到的是-1而不是1。 - user9599745

63

移位运算符

二进制数00101011的32位表示为:

00000000 00000000 00000000 00101011,计算结果如下:

  00000000 00000000 00000000 00101011   >> 2(times)
 \\                                 \\
  00000000 00000000 00000000 00001010

将43的二进制位向右移动2位;左侧填充最高(符号)位。

结果为00001010,十进制值为10。

00001010
    8+2 = 10

15

当你向右移动2位时,你会丢掉最低的2位。因此:

x = 00101011

x >> 2

// now (notice the 2 new 0's on the left of the byte)
x = 00001010

这本质上等同于将 int 值除以 2,两次。

在 Java 中

byte b = (byte) 16;
b = b >> 2;
// prints 4
System.out.println(b);

5
每次向右移动一位相当于除以2,因此两次向右移动相当于除以4。 - Steve Kuo
4
没问题,请问需要翻译成什么语言呢? - user395760
2
@delnan,是的,但那看起来很可怕。 - jjnguy
如果在位移操作后显示左侧填充的0,可能会更清晰一些。 - Jonathon Faust
在Java编程语言中,您无法对“byte”数据类型执行位移操作。 - Eido95
在Java中,当我在终端执行此操作时,会出现错误:incompatible types: possible lossy conversion from int to byte - Zhou Haibo

12

这些示例涵盖了应用于正数和负数的三种类型的移位:

// Signed left shift on 626348975
00100101010101010101001110101111 is   626348975
01001010101010101010011101011110 is  1252697950 after << 1
10010101010101010100111010111100 is -1789571396 after << 2
00101010101010101001110101111000 is   715824504 after << 3

// Signed left shift on -552270512
11011111000101010000010101010000 is  -552270512
10111110001010100000101010100000 is -1104541024 after << 1
01111100010101000001010101000000 is  2085885248 after << 2
11111000101010000010101010000000 is  -123196800 after << 3


// Signed right shift on 626348975
00100101010101010101001110101111 is   626348975
00010010101010101010100111010111 is   313174487 after >> 1
00001001010101010101010011101011 is   156587243 after >> 2
00000100101010101010101001110101 is    78293621 after >> 3

// Signed right shift on -552270512
11011111000101010000010101010000 is  -552270512
11101111100010101000001010101000 is  -276135256 after >> 1
11110111110001010100000101010100 is  -138067628 after >> 2
11111011111000101010000010101010 is   -69033814 after >> 3


// Unsigned right shift on 626348975
00100101010101010101001110101111 is   626348975
00010010101010101010100111010111 is   313174487 after >>> 1
00001001010101010101010011101011 is   156587243 after >>> 2
00000100101010101010101001110101 is    78293621 after >>> 3

// Unsigned right shift on -552270512
11011111000101010000010101010000 is  -552270512
01101111100010101000001010101000 is  1871348392 after >>> 1
00110111110001010100000101010100 is   935674196 after >>> 2
00011011111000101010000010101010 is   467837098 after >>> 3

5

>> 是算术右移操作符。第一个操作数中的所有位将向右移动由第二个操作数指定的位数。结果中最左边的位被设置为与原始数字中最左边的位相同的值。(这样负数仍然保持负数。)

以下是您的具体情况:

00101011
  001010 <-- Shifted twice to the right (rightmost bits dropped)
00001010 <-- Leftmost bits filled with 0s (to match leftmost bit in original number)

4
public class Shift {
 public static void main(String[] args) {
  Byte b = Byte.parseByte("00101011",2);
  System.out.println(b);
  byte val = b.byteValue();
  Byte shifted = new Byte((byte) (val >> 2));
  System.out.println(shifted);

  // often overloked  are the methods of Integer

  int i = Integer.parseInt("00101011",2);
  System.out.println( Integer.toBinaryString(i));
  i >>= 2;
  System.out.println( Integer.toBinaryString(i));
 }
}

输出:

43
10
101011
1010

2

在Java中,您无法像00101011那样编写二进制字面量,因此您可以改为以十六进制编写:

byte x = 0x2b;

要计算 x >> 2 的结果,你只需直接写出这个表达式并打印出结果即可。
System.out.println(x >> 2);

Byte.parseByte("00101011",2)是什么? - stacker
这是在编译时计算还是在运行时产生方法调用的结果? - Mark Byers
2
Java 7 应该添加二进制字面值,例如:0b00101011 - Alan Krueger
@Alan Kreuger:那是个好消息 :) 感谢提供信息。 - Mark Byers

2
byte x = 51; //00101011
byte y = (byte) (x >> 2); //00001010 aka Base(10) 10

2
您可以使用例如此API,如果您想查看数字的bitString表示形式。 Uncommons Math 示例(在jruby中):
bitString = org.uncommons.maths.binary.BitString.new(java.math.BigInteger.new("12").toString(2))
bitString.setBit(1, true)
bitString.toNumber => 14

编辑:更改了 API 链接并添加了一个小例子


上述URL已失效,请将其删除/编辑为正确的网页链接。 - realPK
更新了链接。不过我不确定这是否还回答了那个改变了的问题。 - Joni
您保存了一个带有失效URL的HTTP请求! - realPK

0

00101011 = 43 十进制

class test {    
    public static void main(String[] args){
       int a= 43;       
       String b= Integer.toBinaryString(a >> 2);        
       System.out.println(b);
    }   
}

输出:

101011 变成了 1010


3
请问您能否澄清一下这个答案与其他发布在此处的答案有何不同? - AndyG

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