converting bits in to integer - java

I receive a datapacket containing a byte array and I have to get some integer values from it.
Here is a part of the documentation. Can someone help me please?
This comes in a 4-byte array.
Year from 1990 to 2052 (6 bit), Month from 1 to 12 (4 bit), Day from 1
to 31 (5 bit), Hour from 0 to 23 (5 bit), Minute from 0 to 59 (6 bit),
Second from 0 to 59 (6 bit) Default value: 1 January 2000, 12:00:00
The format of the message is in little endian.

What you need is some bitwise operations. First, construct an int out of the bytes:
int n = b[0] | (b[1] << 8) | (b[2] << 16) | (b[3] << 24);
Then, chop up the int into components. Now, your question does not specify which way do the fields go, right-to-left or left-to-right. That question is related to endianness, but not identical. So let's assume that the fields go from left to right.
Good sense suggests left-to-right. This way the integer representations of time values can be compared - the significance of year bits is more than month bits etc, so when you compare integers that correspond to two moments in time, you get a chronologically correct result.
Here's a mental image for you. This is an integer variable, composed of bits:
f e d c b a 9 8 7 6 5 4 3 2 1 0
-----
offset is 6, length is 3
Let's define a function that takes a arbitrary chunk from an int at a given offset (in bits), with a given length (in bits).
int bits(int n, int offset, int length)
{
//shift the bits rightward, so that the desired chunk is at the right end
n = n >> (31 - offset - length);
//prepare a mask where only the rightmost `length` bits are 1's
int mask = ~(-1 << length);
//zero out all bits but the right chunk
return n & mask;
}
Could've been a one-liner, but I wanted to make it somewhat instructive. Folks in the answers below effectively inline this function, by specifying the shift factor and the mask by hand for each chunk.
Now let's decompose. Assuming n comes from the topmost snippet:
int year = bits(n, 0, 6),
month = bits(n, 6, 4),
day = bits(n, 10, 5),
hour = bits(n, 15, 5),
min = bits(n, 20, 6),
sec = bits(n, 26, 6);
We get the values of the offset by combining the total lengths of the previous fields together. This is under the assumption that the fields go left to right; if they go the other way around, the offset values would be different.
Did that make sense?
EDIT: if the bit chunks go right to leftt, then here's how it'd go:
int sec = bits(n, 0, 6),
min = bits(n, 6, 6),
hour = bits(n, 12, 5),
day = bits(n, 17, 5),
month = bits(n, 22, 4),
year = bits(n, 26, 6);

First, I'd convert this to an integer:
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
int timestamp = ByteBuffer.wrap(byte_array).order(ByteOrder.LITTLE_ENDIAN).getInt();
Next, I'd take it apart:
int yearCode = (timestamp >> 26) & 0b111111;
int monthCode = (timestamp >> 22) & 0b1111;
int dayCode = (timestamp >> 17) & 0b11111;
int hourCode = (timestamp >> 12) & 0b11111;
int minCode = (timestamp >> 6) & 0b111111;
int secCode = (timestamp >> 0) & 0b111111;
The masking in the first line and shifting in the last line are not strictly necessary, but are left in for clarity.
The final step is to add 1900 to the yearCode and you're done!

Assuming you have java 7, you should be able to read the year as
int year = 1990
+ ((b[0] & 0b1000_0000) << 5)
+ ((b[0] & 0b0100_0000) << 4)
+ ((b[0] & 0b0010_0000) << 3)
+ ((b[0] & 0b0001_0000) << 2)
+ ((b[0] & 0b0000_1000) << 1)
+ ((b[0] & 0b0000_0100));
and the month as
int month = 1
+ ((b[0] & 0b1000_0010) << 3)
+ ((b[0] & 0b0100_0001) << 2)
+ ((b[1] & 0b1000_0000) << 1)
+ ((b[1] & 0b0100_0000));
I let you do the others ints in the same way.
I don't have java7 and can't test now, I hope I'm not wrong. It's also possible that the order of the bytes is the reverse one.

Related

The number of non-zero quaternary (base 4) digits in a long?

Let us start simple. Say you want to find how many 1's in a long in its binary representation. For example, how many 1's in 228₁₀? The binary represenation is 11100100₂. We can use Long.bitCount(228); which returns 4.
Now, let us say we will interpret two bits as a single quaternary digit (and the two far-right bits is the first digit):
00₂ = 0₄
01₂ = 1₄
10₂ = 2₄
11₂ = 3₄
Hence, 228₁₀ = 11100100₂ = 3210₄. The goal is to find how many non-zero quaternary digits are there in the binary representation. For examples, 3210₄ yields 3, 121100₄ yields 4, 000032₄ yields 2, etc.
The code of the Long.bitCount(i); method from Java's documentation is given by:
public static int bitCount(long i) {
i = i - ((i >>> 1) & 0x5555555555555555L);
i = (i & 0x3333333333333333L) + ((i >>> 2) & 0x3333333333333333L);
i = (i + (i >>> 4)) & 0x0f0f0f0f0f0f0f0fL;
i = i + (i >>> 8);
i = i + (i >>> 16);
i = i + (i >>> 32);
return (int)i & 0x7f;
}
The goal is to find how many non-zero quaternary digits are there in the binary representation without any types of loops nor the usage of Strings. I am trying to manipulate the code so that it works for quaternary. This is what I currently have:
public static int bitCountQuat(long i) {
i = i - ((i >>> 2) & 0x3333333333333333L);
i = (i & 0x3333333333333333L) + ((i >>> 4) & 0x0f0f0f0f0f0f0f0fL);
i = (i + (i >>> 8)) & 0x00ff00ff00ff00ffL;
i = i + (i >>> 16);
i = i + (i >>> 32);
i = i + (i >>> 64);
return (int) i & 0x7f7f;
}
For more reference: Efficient Implementation of Hamming Weight.
Here are the values from 0 to 9:
Binary, desired output, current output
0000, 0, 0
0001, 1, 2
0010, 1, 4
0011, 1, 6
0100, 1, 6
0101, 2, 0
0110, 2, 2
0111, 2, 4
1000, 1, 4
1001, 2, 6
Start by converting all non-zero quaternary digits to 1s ...
i = (i & 0x5555555555555555L) | ((i >> 1) & 0x5555555555555555L));
... then count the bits in the result.
One way to do that bit count would be to continue from there with
i = (i & 0x3333333333333333L) + ((i >> 2) & 0x3333333333333333L));
i = (i & 0x0f0f0f0f0f0f0f0fL) + ((i >> 4) & 0x0f0f0f0f0f0f0f0fL));
i = (i & 0x00ff00ff00ff00ffL) + ((i >> 8) & 0x00ff00ff00ff00ffL));
i = (i & 0x0000ffff0000ffffL) + ((i >> 16) & 0x0000ffff0000ffffL));
i = (i & 0x00000000ffffffffL) + (i >> 32);
, which are the trailing steps of the implementation presented in the Wikipedia article you referenced.
Alternatively, you could use the (whole) implementation of Long.bitCount(), or even Long.bitCount() itself for the bit counting part. Its variation has enough fewer operations than the (full) Wikipedia version to be about a wash with the above shortcut version.

Reverse bits of a unsigned integer

The below two code is the method can invert the bits of an unsigned 32 bits integer. But What's the difference of the two code below?
Why the first code is wrong and the second code is correct.
I can't see the difference of these two.
public int reverseBits(int n) {
int result = 0;
for (int i = 0; i < 32; i++) {
result = result << 1 | (n & (1 << i));
}
return result;
}
public int reverseBits(int n) {
int result = 0;
for (int i = 0; i < 32; i++) {
result = result << 1 | ((n >> i) & 1);
}
return result;
}
Appreciate any help.
The first code is wrong, because it extracts given bit and puts it in the same position of the resulting number. Suppose you are on iteration i = 5. Then n & (1 << 5) = n & 32 which is either 0 or 0b100000. The intention is to put the one-bit to the lowest position, but when performing | operation it actually puts it to the same position #5. On the consequent iterations you move this bit even higher, so you practically have all the bits or'ed at the highest bit position.
Please note that there are more effective algorithms to reverse bits like one implemented in standard JDK Integer.reverse method:
public static int reverse(int i) {
// HD, Figure 7-1
i = (i & 0x55555555) << 1 | (i >>> 1) & 0x55555555;
i = (i & 0x33333333) << 2 | (i >>> 2) & 0x33333333;
i = (i & 0x0f0f0f0f) << 4 | (i >>> 4) & 0x0f0f0f0f;
i = (i << 24) | ((i & 0xff00) << 8) |
((i >>> 8) & 0xff00) | (i >>> 24);
return i;
}
It has to do with whether the bit being grabbed from n is being stored in the rightmost bit of the result or being stored back into the same position.
Suppose n is 4 (for example).
Then when i is 2, the expression (n & (1 << i))
becomes (4 & (1 << 2)), which should equal 4 & 4, so it evaluates to 4.
But the expression ((n >> i) & 1)
becomes ((4 >> 2) & 1), which should equal 1 & 1, so it evaluates to 1.
The two expressions do not have the same result.
But both versions of the function try to use those results in the exact same way, so the two versions of the function do not have the same result.

Java Signed Right Shift

I have seen this in a java code.
int n = 300 //passed through a function
size = (n + 31) >> 5 //size = 10
what could be the significance of 5?
What is the significance of 31 //should something to do with int size (31 bit + 1 sign)
Thanks
The significance of 5 is that 32 = 2^5.
size = (n + 31) >> 5
sets size to ceiling(n/32), which is the number of 32-bit integers needed to store n bit flags.
The addition of 31 to n is to make sure that the dividend is at least as large as the smallest multiple of 32 greater than or equal to n.

Java bit operations error (convert to byte and convert back)

I'm trying to convert date of birth (three ints) to byte and convert it back but I'm having an issue. I have to convert it by using bit operations and send data over multicast server and receive it and change back to int. Server works fine, but bit operations are hard for me. What's the matter with the code:
Convert:
int D=12;
int M=9;
int Y=1983;
short DMY=0;
DMY = (short)(DMY | (D << 19));
DMY = (short)(DMY | (M << 15));
DMY = (short)(DMY | Y);
byte[] data = new byte[3];
data[0] = (byte)(DMY >>> 8 );
data[1] = (byte)(DMY >>> 16 );
data[2] = (byte)(DMY & 0xffff);
Convert back:
byte[] rec_data = new byte[3];
rec_data = dp.getData();
short Rec_dmy;
Rec_dmy = (short)(rec_data[0] & 0xff);
Rec_dmy = (short) (Rec_dmy << 8);
Rec_dmy = (short)(Rec_dmy | (rec_data[1] & 0xff));
Rec_dmy = (short) (Rec_dmy << 8);
Rec_dmy = (short)(Rec_dmy | (rec_data[2] & 0xffff));
byte tmp = (byte) ((Rec_dmy >>> 19) & 0x1F);
byte tmp2 = (byte) ((Rec_dmy >>> 15) & 0x1FF);
byte tmp3 = (byte) (Rec_dmy & 0x7F);
System.out.println(tmp);
System.out.println(tmp2);
System.out.println(tmp3);
Println gives following answer:
31
-1
63
It's not near original 12 9 1983
Shorts can only hold 16 bits; you are trying to pack more than that (e.g. shifting day left by 19, which will result in an all-zero value once casted to a short). You need to use an int or a long to hold all the fields.
Indeed, you've got several things going on with the bit operations that aren't right.
My suggestion would be to ditch the bit operations and just send the day, month and year as separate fields: one byte for each of the day and month, and two (a short) for the year. That takes 4 bytes (only one extra byte) but requires a lot less fiddling to get right.
Its not easy, but you have to work systematically to ensure your operations don't a) lose information b) decode the reverse of how you have encoded.
int D = 12;
int M = 9;
int Y = 1983;
int DMY = (D << 19) | (M << 15) | Y;
byte[] data = new byte[3];
data[0] = (byte) (DMY >>> 16);
data[1] = (byte) (DMY >>> 8);
data[2] = (byte) DMY;
int DMY2 = ((data[0]&0xFF) << 16) | ((data[1]&0xFF) << 8) | (data[2]&0xFF);
int D2 = DMY2 >>> 19; // no mask required
int M2 = (DMY2 >>> 15) & 0x0F; // 4 bits mask
int Y2 = DMY2 & 0x7FFF; // 15 bit mask
System.out.println(D2 + "/" + M2 + "/" + Y2);
prints
12/9/1983
First, you need at least 14 bits to represent the year with max value 9999 because of 2^14 > 9999 && 2 ^ 13 < 9999. And the least number of bits for month is 4(12 at max), day is 5(31 at max). So you can use a short int(16 bits) to represent year and byte (8 bits) for each day and month. So you get a 32-bits int.
public int encoded(short year, byte month, byte day){
int data =0;
data = year & 0xFFFF;
data =(data << 8)|(month & 0xFF)
data =(data << 8)|(day & 0xFF)
return data;
}
public void decode(int data){
int day = data & 0xFF;
int month = (data >> 8) & 0xFF;
int year = (data >> 16) & 0xFFFF;
}

Sum of the bits in Java

sorry Friends i did a mistake. I have did this mistake again. am really very sorry.
this is the Issue.
I have a time range like
int Starttime = 2 which mean(02:00)
int enttime = 8 which mean(08:00)
i want time in sum of bits,
example
00:00 1
01:00 2
02:00 4 -----
03:00 8 R
04:00 16 a
05:00 32 n
06:00 64 g
07:00 128 e
08:00 256 -----
and soo on till 23:00
so i need totalRange = 256+128+64+32+16+8+4 ;
it should be like this
sorry again.
Thanks
The table indicates that you want to map the hour value of a time to an integer value using this function:
int value = (int) Math.pow(2, hourValue);
or, in other words, 00:00h will map to 20, 12:00h to 212 and so on.
Now if you have need the sum of start and endtime, you can simple use the function from above and add the values:
int totalrange = (int) Math.pow(2, starttime) + (int) Math.pow(2, endtime);
Now if you have starttime=2 and endtime=23, this will give a result (written in binary):
01000000 00000000 00000100
shamelessly adapting polygenelubricants much faster solution:
int totalrange = (1 << starttime) + (1 << endtime);
This works, because 2i is equal to (1 << i).
System.out.println(Integer.toBinaryString(2+24)); // 11010
This uses the Integer.toBinaryString method. There's also toHexString, toOctalString, and a toString with variable radix.
If you need the string to be zero-padded to a specific width, you can write something simple like this:
static String binaryPadded(int n, int width) {
String s = Integer.toBinaryString(n);
return "00000000000000000000000000000000"
.substring(0, width - s.length()) + s;
}
//...
System.out.println(binaryPadded(2+24, 8)); // 00011010
There are different ways to zero pad a string to a fixed width, but this will work for any int value.
For hexadecimal or octal, you can use formatting string instead:
System.out.println(String.format("%04X", 255)); // 00FF
The specification isn't very clear, but it looks like you want this mapping:
0 -> 1
1 -> 2
2 -> 4
3 -> 8
4 -> 16
:
i -> 2i
In that case, your mapping is from i to (1 << i) (the << is the bitwise left-shift operator).
System.out.println(
(1 << 2) + (1 << 4)
); // 20
Note that depending on what is it that you're trying to do, you may also consider using a java.util.BitSet instead.
BitSet demonstration
This may be completely off-the-mark, but assuming that you're doing some sort of interval arithmetics, then BitSet may be the data structure for you (see also on ideone.com):
import java.util.BitSet;
//...
static String interval(BitSet bs) {
int i = bs.nextSetBit(0);
int j = bs.nextClearBit(i);
return String.format("%02d:00-%02d:00", i, j);
}
public static void main(String[] args) {
BitSet workTime = new BitSet();
workTime.set(9, 17);
System.out.println(interval(workTime));
// 09:00-17:00
BitSet stackOverflowTime = new BitSet();
stackOverflowTime.set(10, 20);
System.out.println(interval(stackOverflowTime));
// 10:00-20:00
BitSet busyTime = new BitSet();
busyTime.or(workTime);
busyTime.or(stackOverflowTime);
System.out.println(interval(busyTime));
// 09:00-20:00
}
Note that methods like nextSetBit and nextClearBit makes it easy to find empty/occupied time slots. You can also do intersect, or, and, etc.
This simple example only finds the first interval, but you can make this more sophisticated and do various arithmetics on non-contiguous time intervals.
Integer.toBinaryString(i)
Returns a string representation of the integer argument as anunsigned integer in base 2.
To compute the length of the time-interval, you have to do
int totalrange = endtime - starttime;
Perhaps this is what you're looking for:
int startTime = 2;
int endTime = 24;
int range = endTime - startTime;
System.out.println(range + " can be expressed as the following sum:");
for (int size = 1; range > 0; size <<= 1, range >>= 1)
if ((range & 1) != 0)
System.out.format("+ %02d:00%n", size);
Output:
22 can be expressed as the following sum:
+ 02:00
+ 04:00
+ 16:00

Categories

Resources