Scott Goldthwaite
Scott Goldthwaite

Reputation: 307

Python 2's complement conversion

I have some binary data from my weather station I need to convert to decimal. I have to combine 2 bytes then right shift by 4. Currently I do this as follows:

byte1 = 251
byte2 = 74
result = (byte1 * 256 + byte2) >> 4
print(result)

This works fine when the incoming data is positive, but when it's negative it's in a 2's complement format and the above code doesn't handle it properly. The result is 4020, but I want -76.

How do I get this to handle 2's complement properly?

Upvotes: 0

Views: 70

Answers (1)

Will Lyles
Will Lyles

Reputation: 346

Try:

byte1 = 251
byte2 = 74

byte_mask = ~0xFFFF

if (byte1>=128):
    result = ( ((byte1 << 8) + byte2) | byte_mask ) >> 4
else:
    result = ((byte1 << 8) + byte2) >> 4

More detail:

We all know what 2's complement is... if the left-most bit is a 1, the number is a negative and we should perform 2's complement to get the number. That's the easy part. The hard part is that you're working in Python. Python's numbering is a blessing and a curse because Python's numbers are INFINITE (roughly speaking). We need to somehow set all of the leftmost bits of an infinite number to 1, so you can do:

byte_mask = ~0xFFFF

Now byte_mask is 1111 1111 1111 1111 1111 1111 ..... 0000 0000 0000 0000

If your incoming byte1 is greater than 128 (and thus a negative number), we just OR your byte1byte2 number, giving the intermediate result:

1111 1111 1111 1111 ..... 1111 1011 0100 1010

Which is clearly much closer to what we want. Then shift right 4. (When we shift right, the left-most 4 digits will be filled with 1 of course):

1111 1111 1111 1111 ..... 1111 1111 1011 0100

Which is, in decimal, what you want: -76

Upvotes: 1

Related Questions