简体   繁体   中英

How to get a 14 bit, two's complement value into an Integer or Short and maintain the sign in Java

I have a 14 bit, two's complement value being sent to my java application form a bluetooth device in the form of a byte array.

I am unable to change the format of the data sent from the bluetooth device.

How do I get this value into an Integer or Short and maintain the sign?

A few things I have tried are

Short x = ByteBuffer.wrap(value).getShort();

Integer x = (short)(value[3] & 0xff) | (short)((value[2] << 8) & 0xff00);

The problem I think I encounter with the above code is when I receive a negative number, for example

-8192 (in two's complement 10 0000 0000 0000)

Because the receiving data type is 16 bits it expects the bit that negates the value to be 16 along but seen as what it actually receives is

0010 0000 0000 0000

It considers this 8192 and not -8192.

Simply extract the number from the byte array, ignoring signedness and excess bits completely:

byte[] data = ...
int rawNum = ((data[0] & 0xFF) << 8) | (data[1] & 0xFF);

Now left shift the raw value by (type size - number of valid bits) then right shift using the signed shift operator

int realNum = (rawNum << (32 - 14)) >> (32 - 14);

This will first move the sign bit into the sign bit of the type storing the value (here: int) by shifting left, then when right shifting the sign bit is replicated shift-distance times (as defined by the shift operator).

You should extend the most significant bit to the left.

Offhand: short y = (short)((x & 0b10000000000000 ) > 0 ? ( x | 0b1100000000000000 ) : x);

That is, if the most significant bit (for a 14 bit number) is 1, then the result of the & is going to be non-zero. If so, add the two additional ones to the left with an or. Otherwise leave as is.

I've generated a small example that uses integers, It should be easy to put the short you've retrieved in the integer. I've shown an example using your value variable just to be sure.

/**
 * Expects the value to contain a 2-complement number stored in the
 * least significant bits.
 * The contents of the most significant bits is ignored.
 * @param value the value to convert
 * @param bitSize the size of the 2 complement number in the value
 * @return the converted value
 */
public static int fromTwoComplement(int value, int bitSize) {
    int shift = Integer.SIZE - bitSize;
    // shift sign into position
    int result  = value << shift;
    // Java right shift uses sign extension, but only works on integers or longs
    result = result >> shift;
    return result;
}

public static void main(String[] args) {
    System.out.println(fromTwoComplement(0b00_00_0000_0000_0001, 14));
    System.out.println(fromTwoComplement(0b00_01_1111_1111_1111, 14));
    System.out.println(fromTwoComplement(0b00_10_0000_0000_0000, 14));
    System.out.println(fromTwoComplement(0b00_11_1111_1111_1111, 14));

    // largest negative
    byte[] value = new byte[] { 0b0010_0000,  0b0000_0000 };
    System.out.println(fromTwoComplement((int) ByteBuffer.wrap(value).getShort(), 14));

}
public static void main(String[] args)
{
            System.out.println((short) 0x1FFF);
    // 0001 1111 1111 1111 - maximum positive value

    System.out.println((short) 0x3FFF);
    // 0011 1111 1111 1111 - minimum negative value

    System.out.println((short) 0xF);
    // 0000 0000 0000 1111 - positive 15

    System.out.println((short) 0x3FF1);

    // 0011 1111 1111 0001 - negative 15

    System.out.println(convert14bit((short) 0x3FFF)); // returns -1

    System.out.println(convert14bit((short) 0x3FF1)); // returns -15

}

public static final short convert14bit(short value)
{
    if ((value & 0x2000) > 0)
    {
        // negative number

        return (short) (value | 0xE000);
    }
    else
    {
        return value;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM