检索一个数字

时间:2016-06-02 20:43:12

标签: java bit-manipulation

尝试检索一些数字的位,例如下面字节11的标记位00001 01 1,

(byte) 11 >> 1 << 6 >> 5

但为什么结果是10而不是2?

@EDIT

为了制作下面的方法,@ Yassin Hajaj的解决方案似乎更可行。

public byte getBits(byte b, int from, int to) { // from & to inclusive

  return (byte) (b >> from << (8 - (to - from + 1))) >> (8 - to - 1);
}

getBits((byte) 11, 1, 2); // => 2

或者来自@Andreas的提示更加普遍,

public <T extends Number> long getBits(T n, int from, int to) {

  return n.longValue() >>> from << (64 - (to - from + 1)) >>> (64 - to - 1);
}

getBits((byte) 11, 1, 2); // => 2

4 个答案:

答案 0 :(得分:6)

您没有指定二进制系统的初始编号。利用binary literals,您可以通过在0b前加上数字来解决这个问题。然后代码输出所需的2

byte b = (byte) 0b11 >> 1 << 6 >> 5;
System.out.println(b); // 2

答案 1 :(得分:3)

获取app.get("/service", function(req, res) { request("http://example.com", function(error, response, body) { if (!error && response.statusCode == 200) { var data1 = JSON.parse(body); request("http://123.com", function(error, response, body) { if (!error && response.statusCode == 200) { var data2 = JSON.parse(body); console.log('data1', data1, 'data2', data2); res.render("example.ejs", { data1: data1, data2: data2 }); } }); } }); }); 的另一种方法是在达到2之后强制转换为byte以仅保留该数字的最后8位。

<< 6

答案 2 :(得分:2)

所以你有11个基数10(0b1011又名0x0B)你想要2位和4位?

使用这两位(0x04 + 0x02 = 0x06)

进行按位AND

x = 11 & 0x06;

不需要换挡

答案 3 :(得分:2)

TL; DR 使用b & 6,例如(byte)(11 & 6)。请参阅最后的getBits()实施工作。

首先,将11投射到byte是没有意义的,因为>>运算符会将其强制转回int值。

为了说明您的代码无效的原因,这里有一个显示所有中间步骤的程序:

public static void main(String[] args) {
    for (byte i = 0; i <= 16; i++) {
        int i1 = i >> 1;
        int i2 = i1 << 6;
        int i3 = i2 >> 5;
        System.out.printf("%3d %s -> %3d %s -> %3d %10s -> %3d %s%n", i, bin(i), i1, bin(i1), i2, bin(i2), i3, bin(i3));
    }
}
private static String bin(int value) {
    String s = Integer.toBinaryString(value);
    return "0000000".substring(Math.min(7, s.length() - 1)) + s;
}

输出:

  0 00000000 ->   0 00000000 ->   0   00000000 ->   0 00000000
  1 00000001 ->   0 00000000 ->   0   00000000 ->   0 00000000
  2 00000010 ->   1 00000001 ->  64   01000000 ->   2 00000010
  3 00000011 ->   1 00000001 ->  64   01000000 ->   2 00000010
  4 00000100 ->   2 00000010 -> 128   10000000 ->   4 00000100
  5 00000101 ->   2 00000010 -> 128   10000000 ->   4 00000100
  6 00000110 ->   3 00000011 -> 192   11000000 ->   6 00000110
  7 00000111 ->   3 00000011 -> 192   11000000 ->   6 00000110
  8 00001000 ->   4 00000100 -> 256  100000000 ->   8 00001000
  9 00001001 ->   4 00000100 -> 256  100000000 ->   8 00001000
 10 00001010 ->   5 00000101 -> 320  101000000 ->  10 00001010
 11 00001011 ->   5 00000101 -> 320  101000000 ->  10 00001010
 12 00001100 ->   6 00000110 -> 384  110000000 ->  12 00001100
 13 00001101 ->   6 00000110 -> 384  110000000 ->  12 00001100
 14 00001110 ->   7 00000111 -> 448  111000000 ->  14 00001110
 15 00001111 ->   7 00000111 -> 448  111000000 ->  14 00001110
 16 00010000 ->   8 00001000 -> 512 1000000000 ->  16 00010000

您的高位未被清除,因为它在int值上运行。如果您将所有内容更改为byte,则会获得:

public static void main(String[] args) {
    for (byte i = 0; i <= 16; i++) {
        byte i1 = (byte)(i >> 1);
        byte i2 = (byte)(i1 << 6);
        byte i3 = (byte)(i2 >> 5);
        System.out.printf("%3d %s -> %3d %s -> %4d %s -> %3d %s%n", i, bin(i), i1, bin(i1), i2, bin(i2), i3, bin(i3));
    }
}
private static String bin(byte value) {
    String s = Integer.toBinaryString(value & 0xFF);
    return "0000000".substring(s.length() - 1) + s;
}
  0 00000000 ->   0 00000000 ->    0 00000000 ->   0 00000000
  1 00000001 ->   0 00000000 ->    0 00000000 ->   0 00000000
  2 00000010 ->   1 00000001 ->   64 01000000 ->   2 00000010
  3 00000011 ->   1 00000001 ->   64 01000000 ->   2 00000010
  4 00000100 ->   2 00000010 -> -128 10000000 ->  -4 11111100
  5 00000101 ->   2 00000010 -> -128 10000000 ->  -4 11111100
  6 00000110 ->   3 00000011 ->  -64 11000000 ->  -2 11111110
  7 00000111 ->   3 00000011 ->  -64 11000000 ->  -2 11111110
  8 00001000 ->   4 00000100 ->    0 00000000 ->   0 00000000
  9 00001001 ->   4 00000100 ->    0 00000000 ->   0 00000000
 10 00001010 ->   5 00000101 ->   64 01000000 ->   2 00000010
 11 00001011 ->   5 00000101 ->   64 01000000 ->   2 00000010
 12 00001100 ->   6 00000110 -> -128 10000000 ->  -4 11111100
 13 00001101 ->   6 00000110 -> -128 10000000 ->  -4 11111100
 14 00001110 ->   7 00000111 ->  -64 11000000 ->  -2 11111110
 15 00001111 ->   7 00000111 ->  -64 11000000 ->  -2 11111110
 16 00010000 ->   8 00001000 ->    0 00000000 ->   0 00000000

此处,问题是您从>>获得的符号扩展。即使切换到>>>也无法正常工作,因为>>>仍然会在转变发生前使用符号扩展强制int

要摆脱签名扩展,您必须使用byteint转换为b & 0xFF,因为&会将b强制转换为int {1}}使用符号扩展名,然后按位AND运算符将删除所有这些位。

当然,如果您仍然要使用按位AND,只需使用它来获得所需的结果,即b & 0b00000110(或b & 6)。

出于与上述相同的原因,getBits()方法无效。

解决方案仍然是使用按位AND运算符,但是从提供的fromto值构造位掩码。

这里的技巧是使用(1 << x) - 1来创建x位的掩码,例如5 - &gt; 0b00011111。因此,如果您想要2到4(包括2和4),请构建0x00011111(5!位)和0x00000011(2位),然后将它们XOR以获得0x00011100

public static byte getBits(byte b, int from, int to) {
    if (from < 0 || from > to || to > 7)
        throw new IllegalArgumentException();
    int mask = ((1 << (to + 1)) - 1) ^ ((1 << from) - 1);
    return (byte)(b & mask);
}
  0 00000000 ->   0 00000000
  1 00000001 ->   0 00000000
  2 00000010 ->   2 00000010
  3 00000011 ->   2 00000010
  4 00000100 ->   4 00000100
  5 00000101 ->   4 00000100
  6 00000110 ->   6 00000110
  7 00000111 ->   6 00000110
  8 00001000 ->   0 00000000
  9 00001001 ->   0 00000000
 10 00001010 ->   2 00000010
 11 00001011 ->   2 00000010
 12 00001100 ->   4 00000100
 13 00001101 ->   4 00000100
 14 00001110 ->   6 00000110
 15 00001111 ->   6 00000110
 16 00010000 ->   0 00000000

对于其他原始类型,重载方法:

public static byte getBits(byte value, int from, int to) {
    if (from < 0 || from > to || to > 7)
        throw new IllegalArgumentException();
    int mask = ((1 << (to + 1)) - 1) ^ ((1 << from) - 1);
    return (byte)(value & mask);
}
public static short getBits(short value, int from, int to) {
    if (from < 0 || from > to || to > 15)
        throw new IllegalArgumentException();
    int mask = ((1 << (to + 1)) - 1) ^ ((1 << from) - 1);
    return (short)(value & mask);
}
public static int getBits(int value, int from, int to) {
    if (from < 0 || from > to || to > 31)
        throw new IllegalArgumentException();
    int mask = ((1 << (to + 1)) - 1) ^ ((1 << from) - 1);
    return value & mask;
}
public static long getBits(long value, int from, int to) {
    if (from < 0 || from > to || to > 63)
        throw new IllegalArgumentException();
    long mask = ((1L << (to + 1)) - 1) ^ ((1L << from) - 1); // <-- notice the change to long and 1L
    return value & mask;
}