python - cut a x-bit binary number to a byte (8bit) - python

I am using python 2.7. I need to truncate a binary number from a x-bits to 8 bits (byte)
i will write an example of what i would like to do to make it clear and also because stackexchange doesn't leave me write my question for some reason, example:
0b1010101010100101 -> 0b10100101
i tried this workaround: converting it to string and then cutting it as a sub-string, but i didn't manage to make it working
str_cs = str(bin(cs))
str_cs = str_cs[to_cut:]
but i am facing many problem to convert it back to a binary number...
how would you truncate it?

Simply use a bitwise & with a byte of all 1s:
cs = cs & 0b11111111
# or, if you're feeling daring:
cs &= 0b11111111

Solution of Phydeaux much better but I was doing :
>>> cs=0b1010101010100101
>>> cs=int(bin(cs)[-8:], 2)
>>> bin(cs)
'0b10100101'
Based on what you were trying with str

Related

Python bit manipulation to get usable data out of a lidar sensor

I am trying to write a python driver for a lidar sensor that only has a package for robot OS.
I was able to get the communication working on a Raspberry Pi and I am getting the data that I need.
I never really worked with bytearrays before and even python is pretty new to me.
The received data looks like this (png), but you can take a look at the documentation (pdf) as well.
So if I'm not mistaken, I have to combine three bits into two like this:
[0x5D, 0xC7, 0xD0] => [0x5DC, 0x7D0]
I think the aforementioned robot OS library does this here, but my c++ is even worse than my python :)
After I have the correct data I want to sort it into a 2D array but that's not a problem.
Can you point me in the right direction, or just suggest how to search for a solution?
Thank you for your help
So here's one solution (maybe not the cleanest but it's bit-manipulation so...):
arr = [0x5D, 0xC7, 0xD0]
byte_0 = arr[0] << 4 | (arr[1] >> 4)
byte_1 = (arr[1] & 0xF) << 8 | arr[2]
I'll try to go over this step by step. The three bytes are, in binary representation:
0b0101_1101
0b1100_0111
0b1101_0000
The << operator is the shift-operator. It moves the bits to the left the specified amount. Applying this to the first byte yields:
0b0101_1101 << 4 = 0b0101_1101_0000, effectively appending four zero's at the end.
The >> operator is basically equivalent to the << operator, just shifting it the other way round. It discards bits when they would go below position 0:
0b1100_0111 >> 4 = 0b1100
Finally, the | operator is the logical 'or' operator. It performs a bit-wise or operation where each result bit is '1' if one or both of the initial bits is '1'. It is only '0' when both bits are '0'. We can make use of this to 'override' the contents of the lower four bits of our result so far. Note that I have omitted leading zero's for simplicity, but here are the numbers padded with zeroes
0b0101_1101_0000 | 0b0000_0000_1100 = 0b0101_1101_1100. And there you have your first number. Now note that this is not a byte, rather you now need 12 bits to represent the number.
The same is done with the second byte. The only thing new here is the logical and operator (&). This operator yields '1' only if both bits are '1'. We can use this to mask out a part of interest of the byte:
0b1100_0111 & 0x1111 = 0b0111

Concatenate numbers in binary [duplicate]

This question already has answers here:
Python int to binary string?
(36 answers)
Closed 6 years ago.
When converting a number in binary in Python what you get is the following:
b = bin(77)
print(b) # 0b1001101
When I was expecting 01001101. I am guessing that the b is there to let Python know that this is a binary number and not some integer. And that is ok within Python but what is considered safe practise here if you want to communicate with the outside world? This might be a silly example but online converters for instance do not recognise the above binary.
Would simply removing b always do the trick? Because I seem to be running into problems trying to code the Ascii85 encoder/decoder where concatenations of binary numbers take place. You can take a look at this example here.
My code is this case produces the following:
ch = 'Man '
list_ = [ord(x) for x in ch] # [77, 97, 110, 32]
binary_repr = ''.join(bin(x) for x in list_) # 0b10011010b11000010b11011100b100000
# When it should be 01001101011000010110111000100000
Notice that simply replacing the b with nothing doesn't quite cut it here. This is probably some dumm mistake but can someone clear things up for me?
>>> format(b, '08b')
Where b is your number and '08b' is the number of bit you want to use representing your number, if the parameter is #08b instead of 08b, you get the 0b in front of the number.
use format in every further operation and you should be good!
Doesn't
str(b)[2:]
do the job?
But you'll maybe better do:
"{0:b}".format(77)

Convert Hexadecimal string to long python

I want to get the value of 99997 in big endian which is (2642804992) and then return the answer as a long value
here is my code in python:
v = 99997
ttm = pack('>i', v) # change the integer to big endian form
print ("%x"), {ttm}
r = long(ttm, 16) # convert to long (ERROR)
return r
Output: %x set(['\x00\x01\x86\x9d'])
Error: invalid literal for long() with base 16: '\x00\x01\x86\x9d'
As the string is already in hex form why isn't it converting to a long? How would I remove this error and what is the solution to this problem.
pack will return a string representation of the data you provide.
The string representation is different than a base 16 of a long number. Notice the \x before each number.
Edit:
try this
ttm = pack('>I',v)
final, = unpack('<I',ttm)
print ttm
Notice the use of I, this so the number is treated as an unsigned value
You have to use struct.unpack as a reverse operation to struct.pack.
r, = unpack('<i', ttm)
this will r set to -1652162304.
You just converted the integer value to big endian binary bytes.
This is useful mostly to embed in messages addressed to big-endian machines (PowerPC, M68K,...)
Converting to long like this means parsing the ttm string which should be 0x1869D as ASCII.
(and the print statement does not work either BTW)
If I just follow your question title: "Convert hexadecimal string to long":
just use long("0x1869D",16). No need to serialize it.
(BTW long only works in python 2. In python 3, you would have to use int since all numbers are represented in the long form)
Well, I'm answering to explain why it's bound to fail, but I'll edit my answer when I really know what you want to do.
This is a nice question.
Here is what you are looking for.
s = str(ttm)
for ch in r"\bx'":
s = s.replace(ch, '')
print(int(s, 16))
The problem is that ttm is similar to a string in some aspects. This is what is looks like: b'\x00\x01\x86\x9d'. Supplying it to int (or long) keeps all the non-hex characters. I removed them and then it worked.
After removing the non-hex-digit chars, you are left with 0001869d which is indeed 99997
Comment I tried it on Python 3. But on Python 2 it will be almost the same, you won't have the b attached to the string, but otherwise it's the same thing.

Bitwise functions and concatenating hex strings

I'm testing some of the functionality of bitwise functions in python. I want to see if I can concatenate hex "strings" as a converted integer and save as a new hex string after applying logical bitwise operations.
def hst(self):
ref = 0
href = ['1b','1bfa','001','0010']
for i in range(0,len(href)):
if i > 0:
ref = ref << len(href[i])*4
ref = ref ^ int(href[i],16)
else:
ref = int(href[i],16)
return hex(ref)
I expect 1b1bfa0010010 but I get fa0001010.
Any thoughts as to why and how I might fix this? As I said, I'm just trying to learn how this all works. I don't wish to use any libraries, just what is included without an import statement.
It's not doing the shifting. I see from the print(hex(ref)):
shift: 0x1b00
xor: 0xfa
shift: 0xfa0000
xor: 0xfa0001
shift: 0xfa0001000
xor: 0xfa0001010
shift is happening but not correctly xoring to the right place.
OMG Windows, you suck! I get the wrong answer in windows only. Linux it works. Why does Windows suck so much?! Thank you both for helping!

Python 2,3 Convert Integer to "bytes" Cleanly

The shortest ways I have found are:
n = 5
# Python 2.
s = str(n)
i = int(s)
# Python 3.
s = bytes(str(n), "ascii")
i = int(s)
I am particularly concerned with two factors: readability and portability. The second method, for Python 3, is ugly. However, I think it may be backwards compatible.
Is there a shorter, cleaner way that I have missed? I currently make a lambda expression to fix it with a new function, but maybe that's unnecessary.
Answer 1:
To convert a string to a sequence of bytes in either Python 2 or Python 3, you use the string's encode method. If you don't supply an encoding parameter 'ascii' is used, which will always be good enough for numeric digits.
s = str(n).encode()
Python 2: http://ideone.com/Y05zVY
Python 3: http://ideone.com/XqFyOj
In Python 2 str(n) already produces bytes; the encode will do a double conversion as this string is implicitly converted to Unicode and back again to bytes. It's unnecessary work, but it's harmless and is completely compatible with Python 3.
Answer 2:
Above is the answer to the question that was actually asked, which was to produce a string of ASCII bytes in human-readable form. But since people keep coming here trying to get the answer to a different question, I'll answer that question too. If you want to convert 10 to b'10' use the answer above, but if you want to convert 10 to b'\x0a\x00\x00\x00' then keep reading.
The struct module was specifically provided for converting between various types and their binary representation as a sequence of bytes. The conversion from a type to bytes is done with struct.pack. There's a format parameter fmt that determines which conversion it should perform. For a 4-byte integer, that would be i for signed numbers or I for unsigned numbers. For more possibilities see the format character table, and see the byte order, size, and alignment table for options when the output is more than a single byte.
import struct
s = struct.pack('<i', 5) # b'\x05\x00\x00\x00'
You can use the struct's pack:
In [11]: struct.pack(">I", 1)
Out[11]: '\x00\x00\x00\x01'
The ">" is the byte-order (big-endian) and the "I" is the format character. So you can be specific if you want to do something else:
In [12]: struct.pack("<H", 1)
Out[12]: '\x01\x00'
In [13]: struct.pack("B", 1)
Out[13]: '\x01'
This works the same on both python 2 and python 3.
Note: the inverse operation (bytes to int) can be done with unpack.
I have found the only reliable, portable method to be
bytes(bytearray([n]))
Just bytes([n]) does not work in python 2. Taking the scenic route through bytearray seems like the only reasonable solution.
Converting an int to a byte in Python 3:
n = 5
bytes( [n] )
>>> b'\x05'
;) guess that'll be better than messing around with strings
source: http://docs.python.org/3/library/stdtypes.html#binaryseq
In Python 3.x, you can convert an integer value (including large ones, which the other answers don't allow for) into a series of bytes like this:
import math
x = 0x1234
number_of_bytes = int(math.ceil(x.bit_length() / 8))
x_bytes = x.to_bytes(number_of_bytes, byteorder='big')
x_int = int.from_bytes(x_bytes, byteorder='big')
x == x_int
from int to byte:
bytes_string = int_v.to_bytes( lenth, endian )
where the lenth is 1/2/3/4...., and endian could be 'big' or 'little'
form bytes to int:
data_list = list( bytes );
When converting from old code from python 2 you often have "%s" % number this can be converted to b"%d" % number (b"%s" % number does not work) for python 3.
The format b"%d" % number is in addition another clean way to convert int to a binary string.
b"%d" % number

Categories

Resources