1
votes

I receive datas, from a RS422 communication, in a byte tab (byte[]).

Some of my data are in two's complement binary with the following rules :

Significant bits   Two's complement
MSB  LSB
00000000           0
00000001           + LSB
01111111           + MSB - LSB
10000000           - MSB
10000001           - MSB + LSB
11111111           - LSB     

To convert byte[] data to decimal, in pure binary, I use the following code :

Byte b05 = new Byte(new Integer(0x7A).byteValue()); // I use those bytes for my test
Byte b06 = new Byte(new Integer(0x00).byteValue());

Byte[] byteTabDay = new Byte[2] ;
byteTabDay[0] = b05 ;
byteTabDay[1] = b06 ;    

int valueDay  =  byteTabDay[1] << 8 | byteTabDay[0] ; 
System.out.println("day :" + valueDay); // print 122

But I don't know how to convert, like previously, byte[] that contain two's complement binary data like that:

Byte b20 = new Byte(new Integer(0x00).byteValue());
Byte b21 = new Byte(new Integer(0xFF).byteValue());
Byte b22 = new Byte(new Integer(0x3C).byteValue());

Those data contain, in theory, the value (more or less) : 1176

So I need help cause I don't understand how I can convert my byte data which contains two's complement binary to decimal.

2
Why are you using boxed types everywhere? Don't do Byte b21 = new Byte(new Integer(0xFF).byteValue());, do byte b21 = (byte) 0xFF; - Karol S
I have no idea what your “rules” are trying to say. Your first code snippet suggest a trivial multi-byte int value but it’s not clear why you have trouble doing the same thing you do with two bytes to three bytes. And how do you come to the value 1176.61254? Floating point, really? - Holger
The first snippet can only be a positive value instead of the second snippet that can be a negative or positive value. You're right I can't have a floating point, so my example is 1176 - Fred37b

2 Answers

2
votes

Two's complement binary is the standard for representing numbers with negative numbers included.

For three-bit numbers:

      Base 2     (One's       Two's
                 complement)  complement
000 =  0
001 =  1
010 =  2
011 =  3
100 =  4             -3         -4
101 =  5             -2         -3
110 =  6             -1         -2
111 =  7             -0         -1

Java assumes two's complement: the most significant bit being 1 means negative.. Also in java byte, short, int, long are signed. As an aside, you used the Object wrappers for the primitive types. Primitive types are more immediate.

byte b05 = (byte) 0x7A;
byte b06 = (byte) 0x00; // MSB, positive as < 0x80

nyte[] byteTabDay = new byte[2];
byteTabDay[0] = b05;
byteTabDay[1] = b06;    

int valueDay  =  ((int) byteTabDay[1]) << 8) | (0xFF & byteTabDay[0]); 
System.out.println("day :" + valueDay); // print 122

What one has to do: keep the sign extension of the most significant byte, but for other bytes keep them to 8 bits by masking them with 0xFF.

1
votes

The easiest way to convert an arbitrary byte array containing a two’s complement value to a decimal representation is new BigInteger(bytearray).toString().

This, however, expects the data to be in the big endian byte order. If the data is in little endian order as it seems in your question, you have to reverse it for the use with BigInteger.

byte[] bytearray={ 0x7A, 0x00 };
ByteBuffer b=ByteBuffer.allocate(bytearray.length);
for(int ix=bytearray.length; ix>0; ) b.put(bytearray[--ix]);
System.out.println(new BigInteger(b.array()).toString()); // print 122

If the length of the array matches a standard primitive value type size, you can use ByteBuffer to get the value directly:

byte[] bytearray={ 0x7A, 0x00 };
System.out.println(ByteBuffer.wrap(bytearray)
    .order(ByteOrder.LITTLE_ENDIAN).getShort()); // print 122

However, don’t expect the value 1176.61254 as a result. That’s impossible. If you think that this is the encoded value you will have to adapt your specification. There is no standard three-byte format for floating point values.