In the topic "Using the Bitwise Logical Operators" from Herbert Schildt's Java: The Complete Reference, Schildt makes the conjunction ~a & 0x0f in order to "reduce its value [~a] to less than 16, so it can be printed by use of the binary array".
class BitLogic {
public static void main(String[] args) {
String[] binary = {
"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111",
"1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"
};
int a = 3; // 0 + 2 + 1 or 0011 in binary
int b = 6; // 4 + 2 + 0 or 0110 in binary
/* ... */
int g = ~a & 0x0f;
/* ... */
System.out.println(" ~a = " + binary[g]);
}
}
Output:
~a = 1100
~a, by itself, doesn't exceed 4 bits, because its value is 1100 (or 12, in decimal), and a conjunction between ~a and 0x0f (0000 1111) should be an identity operation, since every bit of ~a is multiplied by one, hence making ~a depending exclusively on its own values. Am I missing something?
So, how does 0x0f reduce the value of ~a to be less than 16? Wouldn't ~a still have the value 1100 without this conjunction?
Thanks to harold for their explanation in the comments and pointed QA that, with a few other resources, made me understand it.
One cannot assume that the compiler inverts just the significant bits upon negation. Ex.:
000...01010has the same value as1010, but its complement is not the inversion of just those significant digits, it's111...10101. Therefore, the complement ofain the code provided is actually111...1100.Consider N the width of bits that represent an integer type: in Java, all integers are signed values, so their range varies from -2N-1 to 2N-1-1, and the most significant bit (MSB), the one in the Nth position, determines the sign of an integer. When turned on, the MSB represents negative values.
So when
awas inverted, its value became111...1100which is equivalent to -4 in decimal, because of the way Java and most other programming languages represent their integers: using an encoding known as two's complement, which means that "negative numbers are represented by inverting (changing 1’s to 0’s and vice versa) all of the bits in a value, then adding 1 to the result. To decode a negative number, first invert all of the bits, then add 1." (Herbert Schildt, Java: The Complete Reference 12th).Finally, by decoding
~ayou'll see that it represents -4, in decimal, and that's why, without using a bit mask (What is bit masking?), it throws anArrayIndexOutOfBoundsExceptionwith the message "Index -4 out of bounds for length 16". So the bitwise AND between~aand0xfis transforming all but the four rightmost bits of~ato 0, to then be assigned tog:That's why
grequires the0xfbitmask in order to successfully access the 12th index of the array.