15

I have a byte array sent via UDP from x-plane. The bytes (4) are all floats or integers… I tried to cast them to floats but no luck so far…

Example array: byte data[41] = {-66,30,73,0};

How do I convert 4 bytes into int or float and doesn't float use 8 bytes?

mskfisher
  • 3,291
  • 4
  • 35
  • 48
JNK
  • 1,753
  • 8
  • 25
  • 37

5 Answers5

27

Note: I recommend @Ophidian's ByteBuffer approach below, it's much cleaner than this. However this answer can be helpful in understanding the bit arithmetic going on.

I don't know the endianness of your data. You basically need to get the bytes into an int type depending on the order of the bytes, e.g.:

int asInt = (bytes[0] & 0xFF) 
            | ((bytes[1] & 0xFF) << 8) 
            | ((bytes[2] & 0xFF) << 16) 
            | ((bytes[3] & 0xFF) << 24);

Then you can transform to a float using this:

float asFloat = Float.intBitsToFloat(asInt);

This is basically what DataInputStream does under the covers, but it assumes your bytes are in a certain order.

Edit - On Bitwise OR

The OP asked for clarification on what bitwise OR does in this case. While this is a larger topic that might be better researched independently, I'll give a quick brief. Or (|) is a bitwise operator whose result is the set of bits by individually or-ing each bit from the two operands.

E.g. (in binary)

   10100000
|  10001100
-----------
   10101100

When I suggest using it above, it involves shifting each byte into a unique position in the int. So if you had the bytes {0x01, 0x02, 0x03, 0x04}, which in binary is {00000001, 00000010, 00000011, 00000100}, you have this:

                                  0000 0001   (1)
                        0000 0010             (2 <<  8)
              0000 0011                       (3 << 16)
  | 0000 0100                                 (4 << 24)
  --------------------------------------------------------
    0000 0100 0000 0011 0000 0010 0000 0001   (67 305 985)

When you OR two numbers together and you know that no two corresponding bits are set in both (as is the case here), bitwise OR is the same as addition.

See Also

Mark Peters
  • 80,126
  • 17
  • 159
  • 190
  • Just a noob side question: What does the "|" do ? – JNK Dec 22 '10 at 21:19
  • @Jesper I know that | means OR in an if statement for example but what exactly happens? – JNK Dec 22 '10 at 21:56
  • This answer is accepted so I don't want to delete it, but the ByteBuffer is a much better solution IMO. Also, my answer was extremely sloppy, and actually wrong (I didn't `& 0xFF` after converting the bytes to integers which meant sign bits were corrupting the conversion). That has been fixed. – Mark Peters Dec 16 '11 at 15:05
22

You probably want to make use of java.nio.ByteBuffer. It has a lot of handy methods for pulling different types out of a byte array and should also handle most issues of endianness for you (including switching the byte order if necessary).

byte[] data = new byte[36]; 
//... populate byte array...

ByteBuffer buffer = ByteBuffer.wrap(data);

int first = buffer.getInt();
float second = buffer.getFloat();

It also has fancy features for converting your byte array to an int array (via an IntBuffer from the asIntBuffer() method) or float array (via a FloatBuffer from the asFloatBuffer() method) if you know that the input is really all of one type.

Ophidian
  • 9,775
  • 2
  • 29
  • 27
  • Forgive my ignorance, but just how could `ByteBuffer` "handle most issues of endianness" for you? How could it *possibly* know whether you as the developer expect `{00,00,00,01}` to represent `1` or `16,777,216`? – Mark Peters Dec 22 '10 at 21:44
  • 6
    Well, of course it can't automagically detect the endianness for you, but after you told it (using `ByteBuffer::order(ByteOrder)`) which endianness to use (by default it uses ByteOrder::BIG_ENDIAN), everything else is taken care of by the ByteBuffer. – Simon Lehmann Dec 22 '10 at 22:49
  • Note: even if the data is of other types. The other array helpers still work. Like if you have an int of the size of the floats, and a bunch of floats. You can putInt(size()) and then push the floats with the floatbuffer. You can have any input type you want, it's just those helpers are best when you have a lot of the same type for a long while. – Tatarize May 22 '17 at 01:06
3

Use a DataInputStream as follows:

    DataInputStream dis = new DataInputStream(new ByteArrayInputStream(data));
    float f = dis.readFloat();

    //or if it's an int:        
    int i = dis.readInt();
dogbane
  • 266,786
  • 75
  • 396
  • 414
  • 3
    Isn't it important to take care of endianness? – khachik Dec 22 '10 at 20:49
  • 1
    DataInputStream uses the following (via JavaDocs): Data input streams and data output streams represent Unicode strings in a format that is a slight modification of UTF-8. (For more information, see X/Open Company Ltd., "File System Safe UCS Transformation Format (FSS_UTF)", X/Open Preliminary Specification, Document Number: P316. This information also appears in ISO/IEC 10646, Annex P.) Note that in the following tables, the most significant bit appears in the far left-hand column. – Berin Loritsch Dec 22 '10 at 20:57
  • @Berin: What on Earth does `DIS`'s handling of UTF-8 have to do with reading a float? – Mark Peters Dec 22 '10 at 21:40
  • @khachick: only if the endianness is different at both ends. DataInputStream assumes network byte order. If the data is in that order that takes care of the endianness. – user207421 Dec 22 '10 at 22:57
  • That paragraph describes the endianness of DataInputStream. That's what it has to do with this topic. – Berin Loritsch Dec 23 '10 at 11:15
3

You cannot just cast them into a float/int. You have to convert the bytes into an int or float.

Here is one simple way to do it:

byte [] data = new byte[] {1,2,3,4};
ByteBuffer b = ByteBuffer.wrap(data);
System.out.println(b.getInt());
System.out.println(b.getFloat());

There is a reasonable discussion here:

http://www.velocityreviews.com/forums/t129791-convert-a-byte-array-to-a-float.html

Vilas
  • 1,405
  • 12
  • 15
0

In my opinion the ByteBuffer approach is better, you can specify where the data is wrapped (from which byte index, here 0) and also the endianness (here BIG_ENDIAN).

try {
    float result = ByteBuffer.wrap(data, 0, 4).order(BIG_ENDIAN).getFloat();
} catch (IndexOutOfBoundsException exception) {
    // TODO: handle exception
}

Functions similar to getFloat() exist for Int, Short, Long...

Arnaud SmartFun
  • 1,573
  • 16
  • 21