7

This feels like it should be very simple, but I haven't been able to find an answer..

In a python script I am reading in data from a USB device (x and y movements of a USB mouse). it arrives in single ASCII characters. I can easily convert to unsigned integers (0-255) using ord. But, I would like it as signed integers (-128 to 127) - how can I do this?

Any help greatly appreciated! Thanks a lot.

6 Answers 6

10

Subtract 256 if over 127:

unsigned = ord(character)
signed = unsigned - 256 if unsigned > 127 else unsigned

Alternatively, repack the byte with the struct module:

from struct import pack, unpack
signed = unpack('B', pack('b', unsigned))[0]

or directly from the character:

signed = unpack('B', character)[0]
Sign up to request clarification or add additional context in comments.

Comments

1
from ctypes import c_int8
value = c_int8(191).value

use ctypes with your ord() value - should be -65 in this case

ex. from string data

from ctypes import c_int8
data ='BF'
value1 = int(data, 16) # or ord(data.decode('hex'))
value2 = c_int8(value1).value

value1 is 16bit integer representation of hex 'BF' and value2 is 8bit representation

1 Comment

Signed integer overflow is undefined in C, so this does not always work (But probably will in all versions of CPython)
1

I know this is an old question, but I haven't found a satisfying answer elsewhere.

You can use the array module (with the extra convenience that it converts complete buffers):

from array import array

buf = b'\x00\x01\xff\xfe'
print(array('b', buf))

# result: array('b', [0, 1, -1, -2])

Comments

1

Use this function to get a signed 8bit integer value

def to8bitSigned(num): 
    mask7 = 128 #Check 8th bit ~ 2^8
    mask2s = 127 # Keep first 7 bits
    if (mask7 & num == 128): #Check Sign (8th bit)
        num = -((~int(num) + 1) & mask2s) #2's complement
    return num

Comments

1

To convert any input bytes into signed integers:

def signed8bit_to_int(input):
    (((input >> 7) * 128) ^ input) - ((input >> 7) * 128)

Examples:
signed8bit_to_int(0xc0) = -64
signed8bit_to_int(0xbf) = -65
signed8bit_to_int(0x0f) = 15

Explanation with 0xC0 as an example:

  • 0xc0 '0b1100 0000', its last bit is a 1, meaning it is a signed byte
  • step 1: test for signed bit: (((input >> 7) * 128)
  • step 2: if it is a signed bit, invert the input bites:
    from: 100 0000 to 0111 1111 (63 of base 10)
  • step 3: convert the above by substantiating 128: 63 - 128 = -65

Comments

0

The question doesn't clearly state if the single character is given as str or bytes.

The following answer is especially useful, if the input is an instance of bytes: Since Python 3.2 there is a class method int.from_bytes:

int.from_bytes(b'\x81', byteorder='big', signed=True)  # -127
int.from_bytes(b'a', byteorder='big', signed=True)  # 97

For 16-bit integers, one would simply pass 2 bytes instead of 1:

int.from_bytes(b'\x81\x80', byteorder='big', signed=True)  # -32384
int.from_bytes(b'ab', byteorder='big', signed=True)  # 24930

Of course, you may need to specify byteorder='little'.

However, if the input is an ASCII character (0 - 128), I don't understand why you want a signed integer, because the result for your input will always be positive anyway (if I'm not mistaken). Python's integers use a flexible amount of bytes.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.