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 ;)
Related
I am wondering how can I turn my 32 character int into a 32-byte array as it is represented.
Example:
I have this int:
int test = 123456789;
And I want to turn it into this:
byte[] Write_Page_Four = new byte[] {
(byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x01, (byte) 0x23, (byte) 0x45,
(byte) 0x67, (byte) 0x89};
Currently, I'm thinking of splitting my int by 2 and just manually assigning them to the byte array but I am having some troubles in doing so, and I believe that this is not the best practice for my problem.
This is what I have ATM, which is returning error and still work on progress though and I could use some advice on it:
String test2 = "01";
String test1 = "0x"+test2;
byte test = Byte.valueOf(test1);
System.out.println("teeeeest-----"+test);
byte[] Write_Page_Four = new byte[] {(byte) test};
And this one is returning an error:
java.lang.NumberFormatException: For input string: "0x01"
What is causing problems
Byte.valueOf doesn't parse data like the Java compiler does: it expects as input as a decimal number.
What you can use however, is Byte.valueOf(String,int) with an arbitrary radix. In that case you can solve it using:
byte test = Byte.valueOf(test2,16); //using test2, not test1
Mind that should not add "0x" in the front. Nevertheless this is an inefficient way to do this.
Ints are 32-bits, not 32-bytes
A second problem is that you state that you can store a number like 12345678901234567890123456789011 into an int. You cannot. An int has 32 bits. This means its representation is limited to more or less 2.1B. So I think you mean you store 12345678901234567890123456789011 in a String?
Number systems
Mind that the number 12345678901234567890123456789011 is not represented internally as (byte) 0x12, (byte) 0x34,... unless you are working with binary coded decimals. This is because a computer uses the binary number system (and thus groups bytes with the hexadecimal representation), whereas humans use the decimal representation. 123456789 for instance will be represented as 0x07,0x5B,0xCD 0x15.
Serializing an int (or other datastructure) using an array of bytes
You can convert an int (and other datatypes) into an array of bytes using this code:
ByteBuffer b = ByteBuffer.allocate(4);
b.putInt(test);
byte[] result = b.array(); //result will be 4 bytes,
//since you can represent any int with four bytes.
Or, in case you want to represent the int like the way you do this, you could use the following method:
int t = test;
byte[] dat = new byte[5];//at most 5 bytes needed
for(int j = 4; test != 0; j--) {
int rm = t%100;
dat[j] = (byte) (rm%10+((rm/10)<<8));
t /= 100;
}
//result is dat
Instead of processing the textual representation of the number I'd recommend to simply calculate the single numbers:
Get two digits of the number each time:
int inp = 1234...;
for(int lowerBound = 1 ; lowerBound < Integer.MAX_VALUE ; lowerBound *= 100)
//twoDigit contains two digits of the input-number
int twoDigit = (inp /lowerBound) % 100;
Transform these two digits into a byte:
byte transform(int i){
if(i == 0)
return 0x00;
int lsd = (i % 10); //least significant digit of the input (decimal)
int msd = (i / 10); //most significant digit
//merge lsd and msd into a single number, where the lower 4 bits are reserved for
//lsd and the higher 4 bits for msd
return lsd | (msd << 4);
}
The complete code would look like this:
import java.util.Arrays;
public class test
{
private static final int BYTES = 4;
public static void main(String[] args){
int v = 12345678;
int at_arr = BYTES - 1;
byte[] result = new byte[BYTES];//int is 32-bit/4 byte long
for(int lowerBound = 1 ; lowerBound < Integer.MAX_VALUE && at_arr > -1; lowerBound *= 100, at_arr--)
result[at_arr] = transformDigits((v / lowerBound) % 100);
for(byte b : result)
System.out.print(" 0x" + Integer.toString(b , 16) + ",");
System.out.println();
}
static byte transformDigits(int i){
if(i == 0)
return 0x00;
int lsd = (i % 10); //least significant digit of the input (decimal)
int msd = (i / 10); //most significant digit
//merge lsd and msd into a single number, where the lower 4 bits are reserved for
//lsd and the higher 4 bits for msd
return (byte) (lsd | (msd << 4));
}
}
This code can be used basically for any integral type, if the types and value of BYTES are updated appropriately.
Here's how to convert an int to a byte[]:
int test = 123456789;
byte[] bytes = new byte[4];
bytes[0] = (byte)(test >> 24);
bytes[1] = (byte)(test >> 16);
bytes[2] = (byte)(test >> 8);
bytes[3] = (byte)test;
System.out.printf("%02x %02x %02x %02x%n", bytes[0], bytes[1], bytes[2], bytes[3]);
Output
07 5b cd 15
You can also inline it, if you want:
int test = 123456789;
byte[] bytes = new byte[] { (byte)(test >> 24),
(byte)(test >> 16),
(byte)(test >> 8),
(byte)test };
System.out.printf("%02x %02x %02x %02x%n", bytes[0], bytes[1], bytes[2], bytes[3]);
I am working with Local Binary Patterns (LBP) which produce numbers in the range 0-255.
That means that they can fit in a byte (256 different values may be included into a byte). So that explains why many (if not all) implementation in java I have found uses byte[] to store these values.
The problem is that since I am interested in the rank of these values when converted to byte (from int for example) they do not keep the previous rank they had (as int for example) since byte are signed (as all but chars in java I think) and so the greater 128 values (127 and after) of the range 0-255 becomes negative numbers. Furthermore I think they are inverted in order (the negative ones).
Some examples to be more specific:
(int) 0 = (byte) 0
(int) 20 = (byte) 20
(int) 40 = (byte) 40
(int) 60 = (byte) 60
(int) 80 = (byte) 80
(int) 100 = (byte) 100
(int) 120 = (byte) 120
(int) 140 = (byte) -116
(int) 160 = (byte) -96
(int) 180 = (byte) -76
(int) 200 = (byte) -56
(int) 220 = (byte) -36
(int) 240 = (byte) -16
My question is whether there is a specific way to maintain the order of int values when converted to byte (meaning 240 > 60 should hold true in byte also -16 < 60!) while keeping memory needs minimum (meaning use only 8bits if that many are required). I know I could consider comparing the byte in a more complex way (for example every negative > positive and if both bytes are negative inverse the order) but I think it's not that satisfactory.
Is there any other way to convert to byte besides (byte) i?
You could subtract 128 from the value:
byte x = (byte) (value - 128);
That would be order-preserving, and reversible later by simply adding 128 again. Be careful to make sure you do add 128 later on though... It's as simple as:
int value = x + 128;
So for example, if you wanted to convert between an int[] and byte[] in a reversible way:
public byte[] toByteArray(int[] values) {
byte[] ret = new byte[values.length];
for (int i = 0; i < values.length; i++) {
ret[i] = (byte) (values[i] - 128);
}
return ret;
}
public int[] toIntArray(int[] values) {
int[] ret = new byte[values.length];
for (int i = 0; i < values.length; i++) {
ret[i] = values[i] + 128;
}
return ret;
}
If you wanted to keep the original values though, the byte comparison wouldn't need to be particularly complex:
int unsigned1 = byte1 & 0xff;
int unsigned2 = byte2 & 0xff;
// Now just compare unsigned1 and unsigned2...
Actually I need to transfer the integer value along with the bitmap via bluetooth.. Now my problem is I need to transfer the integer as single byte value..
Is tat possible to convert int as single byte value.. and retrieve it as a integer there... I tried byteValue() and the casting thing but its not usefull.. If my approach is right just help me out with this or say some other way.
(Each time when I am using casting then it's returning as 65535)
What about this?
public static byte[] intToByteArray(int a)
{
byte[] ret = new byte[4];
ret[3] = (byte) (a & 0xFF);
ret[2] = (byte) ((a >> 8) & 0xFF);
ret[1] = (byte) ((a >> 16) & 0xFF);
ret[0] = (byte) ((a >> 24) & 0xFF);
return ret;
}
and
public static int byteArrayToInt(byte[] b)
{
return (b[3] & 0xFF) + ((b[2] & 0xFF) << 8) + ((b[1] & 0xFF) << 16) + ((b[0] & 0xFF) << 24);
}
If you're completely sure, that your int variable contains a byte value [-128; 127] then it should be as simple as:
int i = 100; // your int variable
byte b = (byte) i;
A single byte (8 bits) can only contain 2^8 unsigned integers, i.e [0, 255]. For signed you loose the first bit and the range becomes [-128, 127]. If your integer fits then a simple cast should work.
for 0-255 numbers.
int i = 200; // your int variable
byte b = (byte)(i & 0xFF);
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
How can I convert a short (2 bytes) to a byte array in Java, e.g.
short x = 233;
byte[] ret = new byte[2];
...
it should be something like this. But not sure.
((0xFF << 8) & x) >> 0;
EDIT:
Also you can use:
java.nio.ByteOrder.nativeOrder();
To discover to get whether the native bit order is big or small. In addition the following code is taken from java.io.Bits which does:
byte (array/offset) to boolean
byte array to char
byte array to short
byte array to int
byte array to float
byte array to long
byte array to double
And visa versa.
ret[0] = (byte)(x & 0xff);
ret[1] = (byte)((x >> 8) & 0xff);
A cleaner, albeit far less efficient solution is:
ByteBuffer buffer = ByteBuffer.allocate(2);
buffer.putShort(value);
return buffer.array();
Keep this in mind when you have to do more complex byte transformations in the future. ByteBuffers are very powerful.
An alternative that is more efficient:
// Little Endian
ret[0] = (byte) x;
ret[1] = (byte) (x >> 8);
// Big Endian
ret[0] = (byte) (x >> 8);
ret[1] = (byte) x;
Figured it out, its:
public static byte[] toBytes(short s) {
return new byte[]{(byte)(s & 0x00FF),(byte)((s & 0xFF00)>>8)};
}
Short to bytes convert method In Kotlin works for me:
fun toBytes(s: Short): ByteArray {
return byteArrayOf((s.toInt() and 0x00FF).toByte(), ((s.toInt() and 0xFF00) shr (8)).toByte())
}
Several methods have been mentioned here. But which one is the best? Here follows some proof that the following 3 approaches result in the same output for all values of a short
// loops through all the values of a Short
short i = Short.MIN_VALUE;
do
{
// method 1: A SIMPLE SHIFT
byte a1 = (byte) (i >> 8);
byte a2 = (byte) i;
// method 2: AN UNSIGNED SHIFT
byte b1 = (byte) (i >>> 8);
byte b2 = (byte) i;
// method 3: SHIFT AND MASK
byte c1 = (byte) (i >> 8 & 0xFF);
byte c2 = (byte) (i & 0xFF);
if (a1 != b1 || a1 != c1 ||
a2 != b2 || a2 != c2)
{
// this point is never reached !!
}
} while (i++ != Short.MAX_VALUE);
Conclusion: less is more ?
byte b1 = (byte) (s >> 8);
byte b2 = (byte) s;
(As other answers have mentioned, watch out for LE/BE).
It depends how you want to represent it:
big endian or little endian? That will determine which order you put the bytes in.
Do you want to use 2's complement or some other way of representing a negative number? You should use a scheme that has the same range as the short in java to have a 1-to-1 mapping.
For big endian, the transformation should be along the lines of:
ret[0] = x/256; ret[1] = x%256;
public short bytesToShort(byte[] bytes) {
return ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).getShort();
}
public byte[] shortToBytes(short value) {
byte[] returnByteArray = new byte[2];
returnByteArray[0] = (byte) (value & 0xff);
returnByteArray[1] = (byte) ((value >>> 8) & 0xff);
return returnByteArray;
}
short to byte
short x=17000;
byte res[]=new byte[2];
res[i]= (byte)(((short)(x>>7)) & ((short)0x7f) | 0x80 );
res[i+1]= (byte)((x & ((short)0x7f)));
byte to short
short x=(short)(128*((byte)(res[i] &(byte)0x7f))+res[i+1]);