So, what I am trying to do is convert a float to a bytearray but I keep on receiving both no input, and EXTREME slowing/freezing of my computer.
My code is
import struct
def float_to_hex(f):
return hex(struct.unpack('<I', struct.pack('<f', f))[0])
value = 5.1 #example value
...
value = bytearray(int(float_to_hex(float(value)), 16)
I found on another article a function to convert floats to hex which is
def float_to_hex(f):
return hex(struct.unpack('<I', struct.pack('<f', f))[0])
and then I converted it from hex to an int.
What is the problem with this? How could I better convert it from a float to bin or bytearray?
It depends what you want, and what you are going to do with it. If all you want is a bytearray then:
import struct
value = 5.1
ba = bytearray(struct.pack("f", value))
Where ba is a bytearray. However, if you wish to display the hex values (which I suspect), then:
print([ "0x%02x" % b for b in ba ])
EDIT:
This gives (for value 5.1):
['0x33', '0x33', '0xa3', '0x40']
However, CPython uses the C type double to store even small floats (there are good reasons for that), so:
value = 5.1
ba = bytearray(struct.pack("d", value))
print([ "0x%02x" % b for b in ba ])
Gives:
['0x66', '0x66', '0x66', '0x66', '0x66', '0x66', '0x14', '0x40']
The result I would want from 5.1 is 0x40 a3 33 33 or 64 163 51 51. Not as a string.
To get the desired list of integers from the float:
>>> import struct
>>> list(struct.pack("!f", 5.1))
[64, 163, 51, 51]
Or the same as a bytearray type:
>>> bytearray(struct.pack("!f", 5.1))
bytearray(b'#\xa333')
Note: the bytestring (bytes type) contains exactly the same bytes:
>>> struct.pack("!f", 5.1)
b'#\xa333'
>>> for byte in struct.pack("!f", 5.1):
... print(byte)
...
64
163
51
51
The difference is only in mutability. list, bytearray are mutable sequences while bytes type represents an immutable sequence of bytes. Otherwise, bytes and bytearray types have a very similar API.
Related
import struct
>>> p = struct.pack("#2I", 7, 10)
>>> p
b'\x07\x00\x00\x00\n\x00\x00\x00'
When I pack the value 10, it returns incorrect value
>>> p = struct.pack("#I", 10)
>>> p
b'\n\x00\x00\x00'
why is it printing out as binary \n,0,0,0
this is correct. I indicates the value has to be packed with 4 bytes and has to be interpreted as unsigned int. So you see 4 byte value in the output.
If you are wondering why you get \n:
struct.pack returns you a bytes object, and when you print bytes object, it represents all bytes that can be printed as ASCII and other values are printed as hex and denoted with \x prefix...
decimal 10 is represented in ASCII as \n.
use hex() method in bytes object to see the non translated hex data.
>>> import struct
>>> struct.pack("#I", 10).hex() # or use .hex(':') to separate bytes while printing
'0a000000'
You can double check this by feeding the output of struct.pack to int.from_bytes
>>> int.from_bytes(struct.pack("#I", 10), 'little')
10
I am using the int.to_bytes method within Python to convert integer values into bytes.
With certain values, this seems to fail. Attached is the output from the Python console:
value = 2050
value.to_bytes(2, 'big')
>>> b'\x08\x02'
value = 2082
value.to_bytes(2, 'big')
>>> b'\x08"'
With a value of 2050, the conversion seems to be correct. But when the value is 2082, for some reason only the upper byte seems to be extracted. Any reason as to why this is happening?
It extracts all bytes. Try
value = 2082
x = value.to_bytes(2, 'big')
print(x[0]) # Output: 8
print(x[1]) # Output: 34
When you convert to string, byte 34 translates to ASCII ", which is what you see.
I have a text file that actually contains hex values stored by a program. For instance the the file.txt would contain:
4D 45 5A 4E 53 41 54
I need to convert the raw data to understand it, specifically I need to take two bytes and convert them into an integer. This is the approach I took:
First I split the text file to an array based on the spaces. Then I converted the array to a byte array.
beacon = beacon.split()
beaconBytes = [byte.encode('utf-8') for byte in beacon]
Now it looks like this:
[b'4D', b'45', b'5A', b'4E', b'53', b'41', b'54']
Since the data is transmitted in little endian, the first two bytes should translate to 0x454d = 17741.
But why does :
int.from_bytes(beaconBytes[0]+beaconBytes[1], byteorder='little', signed=False)
print 892617780? Where did this huge number come from?
The "bytes" object actually has the value of the CHARS '4', 'D', and so on (which is not the same as the value 4, or 13, or other hex values represented by 0-9A-F).
to convert a hex string to an int value you can simply use int with a base of 16, like this:
beacon = '4D 45 5A 4E 53 41 54'.split()
firstValHexStr = beacon[1]+beacon[0] # 454D
firstValInt = int(firstValHexStr,16)
print(firstValInt)
Output:
17741
No need to go through bytes object at all :)
encode does not do what you think it does. It merely changes character encodings. You should convert your hexadecimal strings into integers with int:
bytes = [chr(int(x, 16)).encode() for x in beacon.split()]
#[b'M', b'E', b'Z', b'N', b'S', b'A', b'T']
int.from_bytes(bytes[0]+bytes[1], byteorder='little', signed=False)
#17741
I wanted to convert an object of type bytes to binary representation in python 3.x.
For example, I want to convert the bytes object b'\x11' to the binary representation 00010001 in binary (or 17 in decimal).
I tried this:
print(struct.unpack("h","\x11"))
But I'm getting:
error struct.error: unpack requires a bytes object of length 2
Starting from Python 3.2, you can use int.from_bytes.
Second argument, byteorder, specifies endianness of your bytestring. It can be either 'big' or 'little'. You can also use sys.byteorder to get your host machine's native byteorder.
import sys
int.from_bytes(b'\x11', byteorder=sys.byteorder) # => 17
bin(int.from_bytes(b'\x11', byteorder=sys.byteorder)) # => '0b10001'
Iterating over a bytes object gives you 8 bit ints which you can easily format to output in binary representation:
import numpy as np
>>> my_bytes = np.random.bytes(10)
>>> my_bytes
b'_\xd9\xe97\xed\x06\xa82\xe7\xbf'
>>> type(my_bytes)
bytes
>>> my_bytes[0]
95
>>> type(my_bytes[0])
int
>>> for my_byte in my_bytes:
>>> print(f'{my_byte:0>8b}', end=' ')
01011111 11011001 11101001 00110111 11101101 00000110 10101000 00110010 11100111 10111111
A function for a hex string representation is builtin:
>>> my_bytes.hex(sep=' ')
'5f d9 e9 37 ed 06 a8 32 e7 bf'
The Python documentation for bytearray states:
The bytearray type is a mutable sequence of integers in the range 0 <=
x < 256.
However the following code suggests values can be >= 256. I store a 9 bit binary number which has a maximum value of: 2^9-1 = 512-1 = 511
ba = bytes([0b111111111])
print '%s' % (ba)
The 9 bit binary number is printed as decimal 511:
[511]
I don't know what the intended behavior is, but I assumed the most significant bit(s) would be dropped to give an 8 bit number.
You aren't actually creating a bytearray or a bytes object, you're just creating a string containing '[511]', since bytes in Python 2 is just a synonym for str. In Python 3, you would get an error message:
ValueError: byte must be in range(0, 256)
The following code works in Python 2 or Python 3; note that I'm passing an 8 bit number, so it's in range.
ba = bytearray([0b11111111])
print(repr(ba))
output
bytearray(b'\xff')
code:
a = 511
byte = a.to_bytes(byte length goes here, 'little')
to decode:
a = int.from_bytes(byte, 'little')