I'am struggling again with type conversions in java... i need to read a 5 byte value from a ByteBuffer and store the value in a long.
Therefore I did this:
byte msb = b.get();
int lsb = b.getInt();
System.out.println(msb + " " + lsb);
long number = ((msb << 32)) | (((long) lsb) & 0xFFFFFFFF);
System.out.println(number);
and the log gives me the following result:
1 376263385
376263385
so msb and lsb are read correctly, but if i join them together i only get the lsb value in there. I tried to bitmask the values and tried different types to read from, but that doesnt work either.
That's because the type of msb is byte and when you shift it 32 bits to the left you get a zero (byte is just 8 bits). Change msb type to long and you should be OK.
Try this one
long number = 0;
number = number | (((long) msb << 32));
number = number | ((lsb) & 0xFFFFFFFF);
System.out.println(number);
Remember a byte is just 8 bits long. So when you left shift the byte 32 times the 1 is lost. So you need to cast the msb to long. then do the bitmasking.
Related
i have a java code to read a unsigned integer from high 4bit and another from lower 4bit
byte[] value = getBytes(1);
int first = (value[0] & 0xF0) >> 4;
int second = value[0] & 0x0F;
i have to write those 2 integers(first, second) back to new 1 byte using java.
please help me
Basically:
first << 4 | second
(assuming first and second were obtained with the original code, so they are in the range 0x0..0xF).
However, the result of bitwise operations is int for int operands, so this expression is of type int. You need to cast it to byte:
byte b = (byte) (first << 4 | second)
I'm coding a personal project in Java right now and have recently been using bit operations for the first time. I was trying to convert two bytes into a short, with one byte being the upper 8 bits and the other being the lower 8 bits.
I ran into an error when running the first line of code below.
Incorrect Results
short regPair = (short) ( (byte1 << 8) + (byte2) );
Correct Results
short regPair = (short) ( (byte1 << 8) + (byte2 & 0xFF) );
The expected results were: AAAAAAAABBBBBBBB, where A represents bits from byte1 and B represents bits from byte2.
Using the 1st line of code I would get the typical addition between a bit-shifted byte1 with byte 2 added to it.
Example of incorrect results
byte1 = 11, byte2 = -72
result = 2816 -72
= 2744
When using the line of code which produces the expected results I can get the proper answer of 3000. I am curious as to why the bit-masking is needed for byte2. My thoughts are that it converts byte2 into binary before the addition and then performs binary addition with both bytes.
In the incorrect case, byte2 is promoted to an int because of the + operator. This doesn't just mean adding some zeros to the start of the binary representation of byte2. Since integer types are represented in two's complement in Java, 1s will be added. After the promotion, byte2 becomes:
1111 1111 1111 1111 1111 1111 1011 1000
By doing & 0xFF, you force the promotion to int first, then you keep the least significant 8 bits: 1011 1000 and make everything else 0.
Print the intermediate value directly to see what is going on. Like,
System.out.printf("%d %s%n", ((byte) -72) & 0xFF, Integer.toBinaryString(((byte) -72) & 0xFF));
I get
184 10111000
So the correct code is actually adding 184 (not subtracting 72).
So I totally forgot that byte is singed in Java, therefore when performing math with a variable of this data type it will take the signed interpretation and not the direct value of the bits. By performing byte2 & 0xFF, Java converts the signed byte value into an unsigned int with all but the first 8 bits set as 0's. Therefore you can perform binary addition correctly.
signed byte value 0x11111111 = -1
unsigned byte value 0x11111111 = 255
In both cases byte values are promoted to int in the expression when
it is evaluated.
byte byte1 = 11, byte2 = -72;
short regPair = (short) ( (byte1 << 8) + (byte2) );
(2816) + (-72) = 2744
And even in below expression byte is promoted to int
short regPair = (short) ( (byte1 << 8) + (byte2 & 0xFF) );
2816 + 184 = 3000
Here in this expression there is no concatenation of two bytes like it has been expressed in the above question- AAAAAAAABBBBBBBB, where A represents bits from byte1 and B represents bits from byte2.
Actually -7 & 255 gives 184 which is added to 2816 to give the output 3000.
I'm implementing variable lenght encoding and reading wikipedia about it. Here is what I found:
0x00000080 0x81 0x00
It mean 0x80 int is encoded as 0x81 0x00 2 bytes. That what I cannot understand. Okay, following the algorithm listed there we have.
Binary 0x80: 00000000 00000000 00000000 10000000
We move the sign bit to the next octet so we have and set to 1 (indicating that we have more octets):
00000000 00000000 00000001 10000000 which is not equals to 0x81 0x00. I tried to write a program for that:
byte[] ba = new byte[]{(byte) 0x81, (byte) 0x00};
int first = (ba[0] & 0xFF) & 0x7F;
int second = ((ba[1] & 0xFF) & 0x7F) << 7;
int result = first | second;
System.out.println(result); //prints 1, not 0x80
ideone
What did I miss?
Let's review the algorithm from the Wikipedia page:
Take the binary representation of the integer
Split it into groups of 7 bits, the group with the highest value will have less
Take these seven bits as a byte, setting the MSB (most significant bit) to 1 for all but the last; leave it 0 for the last one
We can implement the algorithm like this:
public static byte[] variableLengthInteger(int input) {
// first find out how many bytes we need to represent the integer
int numBytes = ((32 - Integer.numberOfLeadingZeros(input)) + 6) / 7;
// if the integer is 0, we still need 1 byte
numBytes = numBytes > 0 ? numBytes : 1;
byte[] output = new byte[numBytes];
// for each byte of output ...
for(int i = 0; i < numBytes; i++) {
// ... take the least significant 7 bits of input and set the MSB to 1 ...
output[i] = (byte) ((input & 0b1111111) | 0b10000000);
// ... shift the input right by 7 places, discarding the 7 bits we just used
input >>= 7;
}
// finally reset the MSB on the last byte
output[0] &= 0b01111111;
return output;
}
You can see it working for the examples from the Wikipedia page here, you can also plug in your own values and try it online.
Another Variable length encoding of integers exists and are widely used. For example ASN.1 from 1984 does define "length" field as:
The encoding of length can take two forms: short or long. The short
form is a single byte, between 0 and 127.
The long form is at least two bytes long, and has bit 8 of the first
byte set to 1. Bits 7-1 of the first byte indicate how many more bytes
are in the length field itself. Then the remaining bytes specify the
length itself, as a multi-byte integer.
This encoding is used for example in DLMS COSEM protocol or https certificates. For simple code, you can have a look at ASN.1 java library.
I am trying to construct an IP header.
An IP header has the following fields: Version, IHL, DSCP etc. I would like to populate a Byte Array such that I can store the information in bytes.
Where I get confused however is that the Version field is only 4 bits wide. IHL is also only 4 bits wide. How do I fit the values of both of those fields to be represented as a byte? Do I need to do bitshifting?
E.g. Version = 4, IHL = 5. I would need to create a byte that would equal 0100 0101 = 45h or 69 decimal.
(byte) (4 << 4) | 5
This shifts the value 4 to the left, then sets lower 4 bits to the value 5.
00000100 A value (4)
01000000 After shifting left 4 bits (<< 4)
00000101 Another value (5)
01000101 The result of a bitwise OR (|) of #2 and #3
Because the operands are int types (and even if they were byte values, they'd be promoted to int when operators like | act on them), the final result needs a cast to be stored in a byte.
If you are using byte values as operands in any bitwise operations, the implicit conversion to int can cause unexpected results. If you want to treat a byte as if it were unsigned in that conversion, use a bitwise AND (&):
byte b = -128; // The byte value 0x80, -128d
int uint8 = b & 0xFF; // The int value 0x00000080, 128d
int i = b; // The int value 0xFFFFFF80, -128d
int uintr = (b & 0xFF) | 0x04; // 0x00000084
int sintr = b | 0x04; // 0xFFFFFF84
You can do something like this:
int a = 0x04;
a <<= 4;
a |= 0x05;
System.out.println(a);
which essentially turns 0b00000100 into 0b01000000, then into 0b01000101.
https://docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html
To make a compact field containing both Version and IHL in one byte, try doing
byte b = (byte)((Version << 4) + IHL);
This will only work if Version and IHL are numbers from 0 to 15
Just because a byte is 8 bits and your values can only be a maximum of 4 is not a problem. The extra 4 bits will just always be zeroes.
So if you were storing 1 for example:
0000 0001
or 15 (which is the maximum value right?):
0000 1111
Byte shifting is not possible in Java.
How does bitshifting work in Java?
However, as far as the logic is concerned, if you want the version and IHL in one byte, you could do it using the following
byte value = (byte) (IHL | VERSION << 4);
I am finding it difficult to understand and work with this binary representation in java:
With the help of the user Jon Skeet, I understood that binary representation should be built this way.
Here's a code sample:
public class chack {
public static void main(String[] args) {
int num2=2;
int num3=3;
int num4=4;
int num1=1;
int nirbinary = (num1 << 24) | (num2 << 16) | (num3 << 8) | num4;
System.out.println(nirbinary);
String nir= Integer.toBinaryString(nirbinary);
System.out.println(nir);
}
}
Couple of question:
How does one get num1 (for example) back from an int who is already in this binary
why do I get 16909060 when I print nirbinary- what does it stands for?
How does one get num1 (for example) back from an int who is already in this binary
representation?
Thank you
I am not completely sure what you are missing, so I will just explain how you can convert integers to binary strings back and forth in java.
You can get a binary string from an integer like so:
int i = 1234;
String binString = Integer.toBinaryString(i);
and you can convert the string back to an integer this way:
int iNew = Integer.parseInt(binString, 2);
Note the second argument to Integer.parseInt() is the desired base of the number. 2 is binary, 8 is octal, 10 decimal, etc.
16909060 stands for the number 16909060.
It is (1 * 224) + (2 * 216) + (3 * 28) + 4.
To get num1 back out, just right-shift the result the same amount you left-shifted and mask out the other bytes (not always necessary for num1(*), but for the others):
int num1 = nirbinary >> 24 & 0xFF;
int num2 = nirbinary >> 16 & 0xFF;
int num3 = nirbinary >> 8 & 0xFF;
int num4 = nirbinary & 0xFF;
Note that nirbinary is not "a binary representation". Or more precisely: it's no more or less binary than num1, num2, num3 and num4: internally all numbers (and characters, and booleans, ...) are stored in binary.
(*) note that if num1 is > 127, then you either need to use >>> to do the right-shift or use the & 0xFF in order to ensure that the correct value is restored. The difference between >> and >>> are the "new" bits inserted on the "left" side of the value: With >> they will depend on the highest-value bit (known as sign-extension) and with >>> they will always be 0.
Every int is a number, it's not binary, hex or decimal, it's just a number. the statement (num1 << 24) | (num2 << 16) | (num3 << 8) | num4; is a binary manipulation of 4 ints into another int. It doesn't change the representation of nirbinary to binary, since nirbinary has no representation, because (again) it's just a number.
Integer.toBinaryString(nirbinary) returns the binary representation of nirbinary which means "how would nibinary look like in base-2".
If you have a String which is a binary representation of a number, you could get its value, by using Integer.parseint(yourbinaryrepresentation, yourbase); for example - Integer.parseint(nir, 2);
And another thing:
You can't always get back one of the numbers back from nirbinary, since you performed a bit manipulation that is not reversible, for example:
int i1 = 5; //binary 0101
int i2 = 4; //binary 0100
int i3 = i1 | i2; //binary 0101
you cannot recognize each of your variables (i1, i2) since they have a common bit, i3 could have been the result of or on two other numbers:
int i1 = 1; //binary 0101
int i2 = 4; //binary 0100
int i3 = i1 | i2; //binary 0101
in your case, if each number is smaller than 256, you can reverse it with the following operation:
int myoldnumber = (nirbinary >> previousShift) & 0xff;
for example, to retrieve num1 you can do:
int retrievedNum1 = (nirbinary >> 24) & 0xff;
Here no need to depend only on binary or any other format...
one flexible built in function is available
That prints whichever format you want in your program..
Integer.toString(int,representation);
Integer.toString(100,8) // prints 144 --octal representation
Integer.toString(100,2) // prints 1100100 --binary representation
Integer.toString(100,16) //prints 64 --Hex representation
Integer.toString(100,5) // prints 400 --Base 5
When working with bitshifting and integers I would recommend you think in hexadecimal numbers, that will usually make life a lot easier. Just keep in mind that 8 bits represent 1 byte and 1 byte covers the hex-range from 0x00 to 0xFF
Since num1 to num4 are smaller than 10, their decimal representation is equal to their hex representiation, ie 1 = 0x01, 2 = 0x02 etc..
As I told you: 1 Byte is 8 bits. In your bitshifting operation you always shift multiple of 8.
So 0x01 << 8 => 0x0100
0x01 << 16 => 0x010000
etc.
So you basically only add zero bytes, which of course increases the value.
What you do next is to | them, a bitwise or. This means that two bitfields get modified in such a way that the result has a 1 at one place if at least one of the input values as a 1 there. Since your shifted ints contain only zero at the back, a bitwise or is nothing else then to put the value in this spot.
E.g:
(0x01 << 8) | 0x02
0x01 << 8 will produce 0x0100. Now you simply have to replace the last 00 with 02, since you or them: 0x0102
If you want to recreate the original int, you have to mask the part that int represents (this is easy since the parts do not overlap in your example) and then shift it back.
E.g.
Say ou produced 0x010203 and want to have only 0x02. You now have to mask shift it back 0x010203 >> 8 which will put the 02 in the last part. Now simply mask this last part 0x0102 && 0xFF. This will set all but the last 8 bits to zero
it's basically 1 * 2^24 + 2 * 2^16 + 3 * 2^8 + 4 = 16909060
You can get num1 by doing num1 = nirbinary >> 24.
What did you expect instead?
To get the most significant byte from an int i:
(i >> 24) & 0xff