Fred37b
Fred37b

Reputation: 854

How to convert two's complement binary byte[] to decimal?

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.

Upvotes: 1

Views: 10707

Answers (2)

Joop Eggen
Joop Eggen

Reputation: 109547

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.

Upvotes: 2

Holger
Holger

Reputation: 298143

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.

Upvotes: 1

Related Questions