0

I need some help. I am new to python. I am trying to accomplish the following which is written in C++ in python. Here is what I have:

C++:

uint16_t value = (ReadData[1] << 8 | ReadData[2]);
int num = (short) value;
int total = ((0.89*num)+48.31);

Python:

ReadData = [0]*6
arr = bytes(ReadData)
value = arr2[0:3]

Not sure how to take the array which is spit out like so: b'\xff\xff\xce' to a signed int.

Thank you in advance.

1
  • Can you describe what you want to achieve, semantically? Commented Dec 3, 2015 at 19:55

3 Answers 3

2

Since you're using bytes and bytes literals I'm guessing you're on Python 3, in which case you have a much better general option for converting arbitrary runs of bytes into an int. Python 3 has an amazing all in one-converter. For your example case:

>>> int.from_bytes(b'\xff\xff\xce', 'big', signed=True)
-50

It scales to huge sizes, and runs faster than anything else available.

If you're not using Python 3, it's slightly uglier, but still fairly fast:

import binascii

def int_from_bytes(b):
    x = int(binascii.hexlify(b), 16)
    mask = 1 << (len(b) << 3) - 1
    if x & mask:
        x -= mask << 1
    return x

Which gets the same results as the Python 3 built-in when you do:

>>> int_from_bytes(b'\xff\xff\xce')
-50

Note on performance: A pre-compiled struct.Struct will win, hands down, if it's really as simple as one pad byte followed by a signed short, no variable length nonsense. In that case, you'd precompile the Struct with:

unpacker = struct.Struct('>xh').unpack

Then you can use it like so:

x, = unpacker(b'\xff\xff\xce')

The trailing comma is important (Struct.unpack returns a len 1 tuple in this case, and assigning to x, unpacks the single value into x the most efficient way possible.

Sign up to request clarification or add additional context in comments.

1 Comment

If you really only wanted to process two of the bytes, and you had a value in ReadData that you wanted to skip one byte and take the next two from, you'd do int.from_bytes(ReadData[1:3], 'big', signed=True) (the [1:3] slice pulls out the bytes you wanted) or with the compat hack, int_from_bytes(ReadData[1:3]).
0

Python supports bitwise operations that are very similar to C++. If you have an array of Python ints called ReadData, you can do as follows:

value = (ReadData[1] & 0xFF) << 8 | (ReadData[2] & 0xFF)
total = ((0.89 * value) + 48.31)

The & 0xFF removes everything but the lowest byte of the number, which appears to be what you want.

Comments

0

Use the struct module to interpret a bytes string as C data.

If you want to interpret bytes 1 and 2 of ReadData as big-endian signed 16-bit integar, do:

import struct

ReadData = b'\xff\xff\xce'

# ReadData[1:] takes from ReadData[1] until ReadData[-1] (the last one)
num = struct.unpack('>h', ReadData[1:])
# Now num is -50

Which would be equivalent to:

# Convert ReadData to unsigned int
num = (ReadData[1] & 0xFF) << 8 | (ReadData[2] & 0xFF)

# Change sign, assuming we got 16-bit number
num = num - 0x10000

Converting num to total should be trivial:

total = ((0.89*num)+48.31)

Note however that 0.89 * num will cast it to float, so might want to do instead,

total = int((0.89 * num) + 48.31)

2 Comments

Agree with this if it's really only the two bytes you care about (though manually forcing negative without checking the high bit is poor form in the shift and mask code). If they need to process three (and the slice in the Python pulls all three), then struct can't help much, since it works with power of 2 sizes.
@ShadowRanger, Thanks, without much application knowledge it's difficult to provide a more general/safe answer. And the assumption that ReadData is 3 bytes long sounds as arbitrary as saying that pair (1,2) is your integer, I think.

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.