The bitwise operators operates on integral types (int and long). Before explaining how bitwise operators work, you should have an idea of how integers are represented in the binary form. As mentioned by the official primitive data type tutorials, the int data type is a 32-bit signed 2's complement integer, whose value ranges from -2^32 to 2^32-1, inclusively. On the other hand, the long data type is a 64-bit signed 2's complement integer, whose value ranges from -2^64 to 2^64-1, inclusively. In both cases, the highest order bit of int and long shows the sign of the value and is not part of the numeric value, where 0 being positive and 1 being negative.
For example, an int value of 1 in binary form looks like this
00000000000000000000000000000001while an int value of -1 in binary form looks like this
11111111111111111111111111111111The negative value is transformed in 2 steps:
Step 1: bitwise complement of +1, such that 00000000000000000000000000000001 becomes 11111111111111111111111111111110 Step 2: add 1, such that 11111111111111111111111111111110 becomes 11111111111111111111111111111111Given a negative value, where the highest (leftmost) bit is 1, you can work out what value the binary form represents in 2 steps:
Step 1: bitwise complement of the binary value, such that 11111111111111111111111111111011 becomes 00000000000000000000000000000100 Step 2: add 1, such that 00000000000000000000000000000100 becomes 00000000000000000000000000000101Therefore, the original binary form represents -5.
The bitwise operators
Operator | Name | Example | Result | Description |
---|---|---|---|---|
a & b | and | 6 & 9 | 0 | 1 if both bits are 1, or 0 if either bit is 0 |
a | b | or | 6 | 9 | 15 | 1 if either bit is 1, or 0 if both bits are 0 |
a ^ b | xor | 6 ^ 9 | 15 | 1 if both bits are different, 0 if both bits are the same |
~a | not | ~9 | -10 | Inverts the bits. (equivalent to +1 and then change sign) |
n << p | left shift | 60 << 2 | 240 | Shifts the bits of n left p positions. Zero bits are shifted into the low-order positions. |
n >> p | right shift | 60 >> 2 | 15 | Shifts the bits of n right p positions. If n is a 2's complement signed number, the sign bit is shifted into the high-order positions. |
n >>> p | unsigned right shift | -60 >>> 20 | 4095 | Shifts the bits of n right p positions. Zeros are shifted into the high-order positions. |
Packing and Unpacking
Multiple int values of limited range can be "packed" into one int, by using the bitwise operators. For example, we have the following integer variables age (range 0~255, or 8-bit), gender (0~1, or 1-bit), weight (range 0~255, or 8-bit), and height (range 0-255, or 8-bit). These integers can be packed and unpacked into/from a 32-bit integer like this:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// age is 8-bit | |
// gender is 1-bit | |
// weight is 8-bit | |
// height is 8-bit | |
int age=60, gender=1, weight=82, height=182; | |
int packed1 = 0, packed2 = 0; | |
System.out.println("age in binary form is " + Integer.toBinaryString(age)); | |
System.out.println("gender in binary form is " + Integer.toBinaryString(gender)); | |
System.out.println("weight in binary form is " + Integer.toBinaryString(weight)); | |
System.out.println("height in binary form is " + Integer.toBinaryString(height)); | |
// packing - 2 approaches | |
packed2 |= height; | |
packed2 |= (weight << 8); | |
packed2 |= (gender << 16); | |
packed2 |= (age << 17); | |
packed1 = (((((age << 1) | gender) << 8) | weight) << 8) | height; | |
System.out.println("packed1 in binary form is " + Integer.toBinaryString(packed1)); | |
System.out.println("packed2 in binary form is " + Integer.toBinaryString(packed2)); | |
assert packed1 == packed2; | |
// unpacking | |
assert height == (packed1 & 0xff); | |
assert weight == (packed1 >>> 8 & 0xff); | |
assert gender == ((packed1 >>> 16) & 1); | |
assert age == (packed1 >>> 17); |
Represent boolean values in a byte
Suppose we have 8 boolean values that are true or false, and we want to store them in a single byte, and sent it across the network, and then unpack it and use it to toggle 8 different things:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Test | |
public void representBooleanValuesInSingleByte() { | |
byte[] values = {1, 0, 1, 0, 1, 0, 1, 1}; | |
byte packed = pack(values); | |
System.out.println("packed in binary form is " + Integer.toBinaryString((int) packed)); | |
byte[] unpacked = unpack(packed); | |
assert packed == pack(unpacked); | |
} | |
private static byte pack(byte[] values) { | |
byte result = 0; | |
for (byte value : values) { | |
result = (byte) ((result << 1) | value); | |
} | |
return result; | |
} | |
private static byte[] unpack(byte value) { | |
byte[] result = new byte[8]; | |
for (int i = 0; i < result.length; i++) { | |
result[i] = (byte) ((value >> (7 - i))); | |
} | |
return result; | |
} |
No comments:
Post a Comment