I am working on a file reader and came into a problem when trying to read a short. In short (punintended), java is converting a two bytes I'm using to make the short into an int to do bitwise operations and is converting it in a way to keep the same value. I need to convert the byte into an int in a way that would preserve its value so the bits stayed the same.
example of what's happening:
byte number = -1; //-1
int otherNumber = 1;
number | otherNumber; // -1
example of what I want:
byte number = -1; //-1
int otherNumber = 1;
number | otherNumber; // 129
CodePudding user response:
This can be done pretty easily with some bit magic.
I'm sure you're aware that a short
is 16 bits (2 bytes) and an int
is 32 bits (4 bytes). So, between an integer and a short, there is a two-byte difference. Now, for positive numbers, copying the value of a short
to an int
is effectively copying the binary data, however, as you've pointed out, this is not the case for negative numbers.
Now let's look at how negative numbers are represented in binary. It's a bit confusing, so I'll try to keep it simple. Modern systems use what's called the two's compliment to store negative numbers. Basically all this means that the very first bit in the set of bytes representing the number determines whether or not it's negative. For mathematical purposes, the rest of the bits are inverted and offset 1 bit to the right (since you can't have negative 0). For example, 2
as a short would be represented as 0000 0000 0000 0010
, while -2
would be represented as 1111 1111 1111 1110
. Now, since the bytes are inverted in a negative number, this means that -2
in int
form is the same but with 4 more bytes (16 bits) at the beginning that are all set to 1
.
So, in order to combat this, all we need to do is change the extra 1
s to 0
s. This can be done by simply using the bitwise and operator. This operator goes through each bit checks if the bits at each position in each operand are a 1
or a 0
. If they're both 1
, the bit is flipped to a 0
. If not, nothing happens.
Now, with this knowledge, all we need to do is create another integer where the first four bytes are all 1
. This is fairly simple to do using hexidecimal literals. Since they are an integer by default, we simply need to use this to get four bytes of 1
s. With a single byte, if you were to set every bit to 1
, the max value you can get is 255. 255 in hex is 0xFF
, so 2 bytes would be 0xFFFF
. Pretty simple, now you just need to apply it.
Here is an example that does exactly that:
short a = -2;
int b = a & 0xFFFF;
You could also use Short.toUnsignedInt()
, but where's the fun in that?