I have a byte array of length 3, representing a decimal binary number. My question:
Why is this correct:
(a) int x = (array[0] & 0xff) << 16 | (array[1] & 0xff) << 8 | (array[2] & 0xff);
but this isn't?
(b) int x = array[0] << 16 | array[1] << 8 | array[2];
Let's say array[0] is 01010101. Isn't this what happens?
array[0] & 0xff = 01010101 & 11111111 = 01010101 = array[0]
Why is option b) wrong?
Consider what happens when the most significant bit of array[0] is 1.
For example:
array[0] = (byte)0xff;
System.out.println (array[0] << 16);
System.out.println ((array[0] & 0xff) << 16);
output:
-65536
16711680
array[0] is converted to an int for the sake of the left-shift operator. If it has a negative value as a byte, it will have a negative value as an int, and will have a negative value after the left-shift.
When you perform bit-wise AND with 0xff, you make sure the result will be positive.
Related
I have this line below where byte[] shaBytes with value from a SHA1. The first four is added to result to a number which is used in a while loop. I'm trying to port an objC code to java while the line below results to a negative value such as -2063597568 after several iterations.
long tVar = (shaBytes[0] << 24) + (shaBytes[1] << 16) + (shaBytes[2] << 8) + (shaBytes[3] << 3);
So basically, the while loop loops when
tVar > 0xFFFFFFFFL >> 11
In objC shaBytes is an unsigned char which is used as parameter in a CC_SHA1. In objC the code would loop up 700+ iterations while my port only 3 because tVar becomes negative.
Java doesn't have unsigned bytes. All Java integer types are signed. This means that the left shift of a negative byte will be negative:
byte b = -30;
long x = b << 24;
System.out.printf("x = %d\n", x);
// prints -503316480
On other hand if you convert byte to long everything'll turn out okay:
byte b = -30;
long x = (b & 0xffL) << 24;
System.out.printf("x = %d\n", x);
// prints 3791650816
To convert byte to "unsigned" (remember, there is no unsigned stuff in Java) long value use:
long tVar = ((shaBytes[0] & 0xffL) << 24) + ((shaBytes[1] & 0xffL) << 16) + etc
This'll work because Java long is 64-bit and can handle 24 left shift of 8-bit value without signed/unsigned problems.
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;
}
I have 4bytes of hex values directly without two's complement being applied to signed inetger. How do I get an int value from hex bytes using java.
Doesn't this work?
int value = ((0xff & b4) < 24) | ((0xff & b3) < 16) | ((0xff & b2) < 8) | (0xff & b1);
Use a Long. You can't use an int as it's always signed and 4 bytes just won't fit.
Long l = Long.parseLong("FFFFFFFF", 16);
I have some data in int variables in Java (range between 0 and 64000). How to convert to byte this integer? I need just two lower bytes from int (range is ok). How to extract this?
You can get the lowest byte from the integer by ANDing with 0xFF:
byte lowByte = (byte)(value & 0xFF);
This works because 0xFF has zero bits everywhere above the first byte.
To get the second-lowest-byte, you can repeat this trick after shifting down all the bits in the number 8 spots:
byte penultimateByte = (byte)((value >> 8) & 0xFF);
You don't have to do AND operation to get the lower byte just cast it to the byte and get the lower byte in the byte variable.
try following both will give you same result
short value = 257;
System.out.println(value);
byte low = (byte) value;
System.out.println("low: " + low);
byte high = (byte)(value >> 8);
System.out.println("high: " + high);
value = 257;
System.out.println(value);
low = (byte) (value & 0xFF);
System.out.println("low: " + low);
high = (byte) ((value >> 8) & 0xFF);
System.out.println("high: " + high);
or try it on Ideone.com
Given
private int width = 400;
private byte [] data = new byte [2];
I want to split the integer "width" into two bytes and load data[0] with the high byte and data[1] with the low byte.
That is binary value of 400 = 1 1001 0000
so data[0] should contain 0000 0001
and data[1] should contain 1001 0000
Using simple bitwise operations:
data[0] = (byte) (width & 0xFF);
data[1] = (byte) ((width >> 8) & 0xFF);
How it works:
& 0xFF masks all but the lowest eight bits.
>> 8 discards the lowest 8 bits by moving all bits 8 places to the right.
The cast to byte is necessary because these bitwise operations work on an int and return an int, which is a bigger data type than byte. The case is safe, since all non-zero bits will fit in the byte. For more information, see Conversions and Promotions.
Edit: Taylor L correctly remarks that though >> works in this case, it may yield incorrect results if you generalize this code to four bytes (since in Java an int is 32 bits). In that case, it's better to use >>> instead of >>. For more information, see the Java tutorial on Bitwise and Bit Shift Operators.
For converting two bytes the cleanest solution is
data[0] = (byte) width;
data[1] = (byte) (width >>> 8);
For converting an integer to four bytes the code would be
data[0] = (byte) width;
data[1] = (byte) (width >>> 8);
data[2] = (byte) (width >>> 16);
data[3] = (byte) (width >>> 24);
It doesn't matter whether >> or >>> is used for shifting, any one bits created by sign extension will not end up in the resulting bytes.
See also this answer.
This should do what you want for a 4 byte int. Note, it stores the low byte at offset 0. I'll leave it as an exercise to the reader to order them as needed.
public static byte[] intToBytes(int x) {
byte[] bytes = new byte[4];
for (int i = 0; x != 0; i++, x >>>= 8) {
bytes[i] = (byte) (x & 0xFF);
}
return bytes;
}
Integer is 32 bits (=4 bytes) in java, you know?
width & 0xff will give you the first byte,
width & 0xff00 >> 8 will give you the second, etc.
To get the high byte, shift right by 8 bits then mask off the top bytes. Similarly, to get the low byte just mask off the top bytes.
data[0] = (width >> 8) & 0xff;
data[1] = width & 0xff;
int width = 400;
byte [] data = new byte [2];
data[0] = (byte) ((width & 0xFF00) >> 8);
data[1] = (byte) (width & 0xFF);
for(int b = 0; b < 2; b++) {
System.out.println("printing byte " + b);
for(int i = 7; i >= 0; i--) {
System.out.println(data[b] & 1);
data[b] = (byte) (data[b] >> 1);
}
}
I suggest you have a look at the source for HeapByteBuffer. It has the conversion code for all primitive data types. (In fact you could just use a ByteBuffer ;)