Convert float to byte python

Преобразование python float в байты

Я хочу преобразовать число с плавающей точкой Python в байтовый массив, кодируя его как 32-разрядное число с плавающей точкой IEEE с прямым порядком байтов, чтобы записать его в двоичный файл.

Как современный Pythonic способ сделать это в Python 3? Для целых я могу сделать my_int.to_bytes(4,’little’) , но для поплавков нет метода to_bytes .

Еще лучше, если я могу сделать это за один выстрел для каждого float в массиве numpy (с dtype numpy.float32). Но обратите внимание, что мне нужно получить его как байтовый массив, а не просто записать массив в файл сразу.

Есть несколько вопросов с похожим звучанием, но в основном они касаются получения шестнадцатеричных цифр, а не записи в двоичный файл.

4 ответа

Право dtype позволяет записать буфер данных массива в строку байтов или в двоичный файл:

In [449]: x = np.arange(4., dtype=' 
In [460]: x.astype('>f4').tostring() Out[460]: b'\x00\x00\x00\x00?\x80\x00\x00@\x00\x00\x00@@\x00\x00' 

Массивы NumPy поставляются с tobytes метод, который дает вам дамп их необработанных байтов данных:

Вы можете указать аргумент order , чтобы использовать C-порядок (основной ряд) или F-порядок (основной столбец) для многомерных массивов.

Поскольку вы хотите сбросить байты в файл, вас также может заинтересовать tofile , который выгружает байты в файл напрямую:

tofile всегда использует C-порядок.

Если вам нужно изменить порядок байтов, вы можете использовать < > метод. ( newbyteorder имеет более удобную подпись, но не меняет базовые байты, поэтому это не повлияет на tobytes .)

import sys if sys.byteorder=='big': arr = arr.byteswap() data_bytes = arr.tobytes() 

Вы можете использовать struct для pack типа bytes ,

>>> import struct >>> struct.pack('>> struct.pack('>f', 3.14) # big-endian b'@H\xf5\xc3' 

В numpy есть методы save/savez :

Сохраните данные на диск и загрузите их снова:

>>> np.save('/tmp/123', np.array([[1, 2, 3], [4, 5, 6]])) >>> np.load('/tmp/123.npy') array([[1, 2, 3], [4, 5, 6]]) 

Сохраните сжатые данные на диск и загрузите их снова:

>>> a=np.array([[1, 2, 3], [4, 5, 6]]) >>> b=np.array([1, 2]) >>> np.savez('/tmp/123.npz', a=a, b=b) >>> data = np.load('/tmp/123.npz') >>> data['a'] array([[1, 2, 3], [4, 5, 6]]) >>> data['b'] array([1, 2]) >>> data.close() 

Источник

Python: How to Convert a Float to Binary (2 Ways)

This concise article shows you 2 different ways to convert a float to binary in Python (both of these methods only use built-in features of Python and don’t require any third-party libraries).

Читайте также:  Print collections in java

Using the struct module

This approach is a two-step process:

  1. Pack the float as a binary string by using the struct.pack() function.
  2. Use the format() function and list comprehension to convert each byte to binary, then join them together.
import struct # your float number number = 2023.12345 # pack the float as a binary string s = struct.pack('!f', number) # convert each byte to binary and join them b = ''.join(format(c, '08b') for c in s) print(b)
01000100111111001110001111110011

If you have to complete this task many times in the future, you can define a function like this:

def float_to_binary(input: float) -> str: return ''.join(format(c, '08b') for c in struct.pack('!f', input))

Using the decimal module

  1. Use the decimal module to convert your float to a decimal object with fixed precision.
  2. Multiply the decimal object by a power of 2 to get an integer.
  3. Convert the result to binary by calling the bin() function.
from decimal import Decimal, getcontext my_float = 2023.12345 # set the precision to 24 bits getcontext().prec = 24 # convert the float to a decimal object d = Decimal(my_float) # multiply by 2^23 and convert to integer i = int(d * (1 
0b1111110011100011111100110100110101

You can also define a function for reusability:

def float_to_binary(input: float) -> str: getcontext().prec = 24 d = Decimal(input) i = int(d * (1 

This tutorial ends here. As said earlier, it is super concise. Happy coding & have a nice day!

Источник

Convert float to byte python

Hello, as mentioned below is test code for conversion. It is written in Python 2.
What is wrong with second method? It is used for conversion byte array recived over RS485 network and it doesn't work when sent value is around 0 (zero), when value is greater then 0, everything works OK.
Thanks in advance.

import array import struct a = 0.0 def convert_long_to_bytes(i): i = i % 4294967296 n4 = i % 256 i = i / 256 n3 = i % 256 i = i / 256 n2 = i % 256 n1 = i / 256 return (n1, n2, n3, n4) def convert_float_to_MICROCHIP_32bit(x): x_IEEE = struct.pack(">f", x).encode("hex") bits = bin(int(x_IEEE, 16))[2:].zfill(len(x_IEEE) * 4) i = 0 val = list(" ") b_s = bytearray(val) for char in bits: current_bit = int(char) if current_bit == 1: if (i > 0) and (i < 9): b_s[i - 1] = "1" elif i == 0: b_s[8] = "1" else: b_s[i] = "1" else: if (i >0) and (i < 9): b_s[i - 1] = "0" elif i == 0: b_s[8] = "0" else: b_s[i] = "0" i = i + 1 val = str(b_s) hex_val = int(val, 2) bytes_val = convert_long_to_bytes(hex_val) return bytes_val def convert_MICROCHIP_32bit_to_float(x): x_hex = format(x, 'x') bits = bin(int(x_hex, 16))[2:].zfill(len(x_hex) * 4) i = 0 val = list(" ") b_s = bytearray(val) for char in bits: current_bit = int(char) if current_bit == 1: if i < 8: b_s[i + 1] = "1" elif i == 8: b_s[0] = "1" else: b_s[i] = "1" else: if i < 8: b_s[i + 1] = "0" elif i == 8: b_s[0] = "0" else: b_s[i] = "0" i = i + 1 val = str(b_s) hex_val = hex(int(val, 2))[2:].rstrip("L") float_val = struct.unpack('!f', hex_val.decode('hex'))[0] return float_val b = convert_float_to_MICROCHIP_32bit(a) print b c = convert_MICROCHIP_32bit_to_float(b) print c

davef21370 Posts: 897 Joined: Fri Sep 21, 2012 4:13 pm Location: Earth But Not Grounded

Re: Conversion float to byte and backward

When you say "it doesn't work" are you getting an error? How exactly does it not work?

btw, a neater method for splitting a long into bytes would be

n = 1234567890 result = [n >> a & 0xff for a in (24,16,8,0)] print result

Re: Conversion float to byte and backward

(0L, 0L, 0L, 0L) Traceback (most recent call last): File "/home/pi/Desktop/Razno/test_1.py", line 82, in c = convert_MICROCHIP_32bit_to_float(b) File "/home/pi/Desktop/Razno/test_1.py", line 52, in convert_MICROCHIP_32bit_to_float x_hex = format(x, 'x') ValueError: Unknown format code 'x' for object of type 'str'

Re: Conversion float to byte and backward

Not really ploughed my way through your code to figure out what it's trying to do, but when I use format I generally do something like this

PS have you looked at ready-made modules such as binascii (don't know if it would help, but may be others similar)?

Re: Conversion float to byte and backward

I know this type of conversion is almost unique, I did searching over net and with help of many sources code above was put together. I thought for at least half a year it is good, but recently situation with variable = 0 showed up an I got this error.
Program is not stopped, just an error appeared. At the moment (with my knowledge) the only possible solution is to make sure that slave's variable which produce troubles will never be 0, instead of that there is very small value which doesn't impact much on final result.
Thanks for your help,

Re: Conversion float to byte and backward

OK, I still feel there must be a more direct way.
But looking at your code, you seem to be returning a tuple of four integers from your first function so you need to expand this by some means when converting to your hex, something like
x_hex = ''.format(*x)
But this can have only 7 characters which then throws the bit filling out. So you need to pad with zeros
x_hex = ''.format(*x)

PS you can trim and speed up your code in various ways. For instance

 b_s = bytearray(list("00000000000000000000000000000000")) for char in bits: if i < 8: b_s[i+1] = char elif i == 8: b_s[0] = char else: b_s[i] = char i = i + 1 val = str(b_s) 

Re: Conversion float to byte and backward

Thanks for the tip, I'll try it later of this day.
When this code was put together, I was not focused on speed but mostly on functionality, to get some results. Project contains RPi2 as a master in RS485 network with six slaves, which are collecting measuring data of temperatures, air pressure, air moisture, consumption of electric energy, consumption of water and so on. In this stage I manage to build simple GUI, made with QT4, with some labels, buttons, check buttons, graphs, .
Optimization of speed is on delay at the moment.

Danilk Posts: 108 Joined: Wed Feb 01, 2017 7:47 pm Location: Russia, St-Peterburg

Re: Conversion float to byte and backward

Re: Conversion float to byte and backward

 b_s = bytearray(list("00000000000000000000000000000000")) for char in bits: if i < 8: b_s[i+1] = char elif i == 8: b_s[0] = char else: b_s[i] = char i = i + 1 val = str(b_s)

racpi Posts: 33 Joined: Mon Dec 30, 2013 11:54 am Location: australia

Re: Conversion float to byte and backward

from ctypes import * import array import struct import binascii class ieeef(Structure): _fields_ = [ ("fdata",c_float)] class calf(Union): _fields_ = [("data", ieeef), ("hdata",c_ubyte *4 )] def str2barray(S): try: return bytearray.fromhex(S) except ValueError: return None def barray2str(B): return binascii.b2a_hex(B) def ieee2ccs(d): #c_ubyte_Array #ieee754 bytearray to ccs(microchip float) j = bytearray(d) sb=j[3]&128 lse=j[2]&128 j[3]&=127 j[3]>=1 if lse : j[2]|=128 else: j[2]&=127 if sb: j[3]|=128 else: j[3]&=127 return j tp=calf() #raw_bytes =(c_ubyte*4)(*( [0xAE,0x47,5,0x41]))#8.32999992371 raw_bytes =(c_ubyte*4)(*( [0,0,0x48,0x42]))#50.0 tp.hdata=raw_bytes print "value",tp.data.fdata print "as ieee",barray2str(tp.hdata) m = ieee2ccs(tp.hdata) print "as ccs",hex (m[0]),hex(m[1]),hex(m[2]),hex(m[3]) m = ccs2ieee(m) print"back to ieee",hex (m[0]),hex(m[1]),hex(m[2]),hex(m[3]) raw_bytes =(c_ubyte*4)(*( m)) tp.hdata=raw_bytes print "value",tp.data.fdata tp.data.fdata=.001 print "near 0 value",tp.data.fdata print "as ieee",barray2str(tp.hdata) m = ieee2ccs(tp.hdata) print "as ccs",hex (m[0]),hex(m[1]),hex(m[2]),hex(m[3]) m = ccs2ieee(m) print "back to ieee",hex (m[0]),hex(m[1]),hex(m[2]),hex(m[3]) raw_bytes =(c_ubyte*4)(*( m)) tp.hdata=raw_bytes print "value",tp.data.fdata

result============== RESTART: C:/Users/rc/Documents/python/mctoiee.py ==============
value 50.0
as ieee 00004842
as ccs 0x0 0x0 0x48 0x84
back to ieee 0x0 0x0 0x48 0x42
value 50.0
near 0 value 0.0010000000475
as ieee 6f12833a
as ccs 0x6f 0x12 0x3 0x75
back to ieee 0x6f 0x12 0x83 0x3a
value 0.0010000000475
>>>

Re: Conversion float to byte and backward

Ah, not *that* bit. I meant the bit in convert to float, but convert to 32bit also can be stripped down in the same way. I realise that optimising code for speed is not generally a good idea until speed has become an issue. but optimising code for simplicity and readability is always good, mainly for debugging. I found there was a similar issue with non-zero-padding with your later hex() function (which also sticks an unhelpful '0x' on the start of the string) evident with very small numbers.

import array import struct def convert_long_to_bytes(i): i = i % 4294967296 n4 = i % 256 i = i / 256 n3 = i % 256 i = i / 256 n2 = i % 256 n1 = i / 256 return (n1, n2, n3, n4) def convert_float_to_MICROCHIP_32bit(x): x_IEEE = struct.pack(">f", x).encode("hex") bits = bin(int(x_IEEE, 16))[2:].zfill(len(x_IEEE) * 4) i = 0 val = list("00000000000000000000000000000000") b_s = bytearray(val) for char in bits: if (i > 0) and (i < 9): b_s[i - 1] = char elif i == 0: b_s[8] = char else: b_s[i] = char i = i + 1 val = str(b_s) hex_val = int(val, 2) bytes_val = convert_long_to_bytes(hex_val) return bytes_val def convert_MICROCHIP_32bit_to_float(x): x_hex = ''.format(*x) bits = bin(int(x_hex, 16))[2:].zfill(len(x_hex) * 4) i = 0 val = list("00000000000000000000000000000000") b_s = bytearray(val) for char in bits: if i < 8: b_s[i + 1] = char elif i == 8: b_s[0] = char else: b_s[i] = char i = i + 1 val = str(b_s) hex_val = ''.format(int(val, 2)).rstrip("L") float_val = struct.unpack('!f', hex_val.decode('hex'))[0] return float_val for a in (123456789, 0.0, 12.345, 0.00000000000000000000000000001): b = convert_float_to_MICROCHIP_32bit(a) print b c = convert_MICROCHIP_32bit_to_float(b) print c 

Источник

Оцените статью