Conversion

California
Posts: 201
Joined: Sat Jun 06, 2015 2:33 pm

Conversion

Hello, I am facing with mooving some code from python 2 to python 3. Code below works just ok in python 2 but not in python 3.
So your help would be very appreciated.

Code: Select all

``````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):
print ("x", x)
x_IEEE = struct.pack(">f", x).encode("hex")
print ("x_IEEE", x_IEEE)
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
bin_val = str(b_s)
print ("bin_val", bin_val)
hex_val = int(bin_val, 2)
print ("hex_val", hex_val)
bytes_val = convert_long_to_bytes(hex_val)
print ("bytes_val", bytes_val)
return bytes_val

a = 987654321.123456789  #-987654321.123456789  #0.0  #-5.1  #5.1
b = convert_float_to_MICROCHIP_32bit(a)
print b
``````

jahboater
Posts: 6512
Joined: Wed Feb 04, 2015 6:38 pm
Location: Wonderful West Dorset

Re: Conversion

You may need // instead of / for integer division.

California
Posts: 201
Joined: Sat Jun 06, 2015 2:33 pm

Re: Conversion

the first error is:

Code: Select all

``````Traceback (most recent call last):
File "/home/pi/Desktop/convert_float_to_MICROCHIP_32bit_py27.py", line 47, in <module>
b = convert_float_to_MICROCHIP_32bit(a)
File "/home/pi/Desktop/convert_float_to_MICROCHIP_32bit_py27.py", line 15, in convert_float_to_MICROCHIP_32bit
x_IEEE = struct.pack(">f", x).encode("hex")
AttributeError: 'bytes' object has no attribute 'encode'``````

billio
Posts: 71
Joined: Thu Dec 15, 2011 8:25 am
Contact: Website

Re: Conversion

I think you need

Code: Select all

``struct.pack(">f", x).hex()``
as described here https://docs.python.org/3/library/stdtypes.html
The type 'bytes' does not have an encode() function in python3.

California
Posts: 201
Joined: Sat Jun 06, 2015 2:33 pm

Re: Conversion

Thanks for your answer, it alows me to go forward through the code execution - almost to the end.
Code looks now:

Code: Select all

``````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).hex()
bits = bin(int(x_IEEE, 16))[2:].zfill(len(x_IEEE) * 4)
i = 0
val = "                                ".encode()
b_s = list(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
bin_val = [int(i) for i in b_s]
out = 0
for bit in bin_val:
out = (out << 1) | bit
hex_val = hex(out)
bytes_val = convert_long_to_bytes(hex_val)
return bytes_val

a = 5.1 #987654321.123456789  #-987654321.123456789  #0.0  #-5.1
b = convert_float_to_MICROCHIP_32bit(a)
print (b)``````
and the last error message:

Code: Select all

``````Traceback (most recent call last):
File "/home/pi/Desktop/convert_float_to_MICROCHIP_32bit_py34.py", line 45, in <module>
b = convert_float_to_MICROCHIP_32bit(a)
File "/home/pi/Desktop/convert_float_to_MICROCHIP_32bit_py34.py", line 41, in convert_float_to_MICROCHIP_32bit
bytes_val = convert_long_to_bytes(hex_val)
File "/home/pi/Desktop/convert_float_to_MICROCHIP_32bit_py34.py", line 4, in convert_long_to_bytes
i = i % 4294967296
TypeError: not all arguments converted during string formatting``````

B.Goode
Posts: 10902
Joined: Mon Sep 01, 2014 4:03 pm
Location: UK

Re: Conversion

I can't solve it, but can refer you to the likely cause:

In addition to performing the modulo operation on numbers, the % operator is also overloaded by string and unicode objects to perform string formatting (also known as interpolation). The syntax for string formatting is described in the Python Library Reference, section String Formatting Operations.
Ref: https://docs.python.org/2/reference/expressions.html

(Similar text for the Python3 version of the documentation.)

So it looks as though the argument being passed into your convert_long_to_bytes() function is being treated as a string, or a unicode object, by Python3?

California
Posts: 201
Joined: Sat Jun 06, 2015 2:33 pm

Re: Conversion

Well, it's strange for me. Code below works ok, but together with the rest of the code lines error is shown.
BTW, result is correct.

Code: Select all

``````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

n1 = int(round(n1))
n2 = int(round(n2))
n3 = int(round(n3))
n4 = int(round(n4))
return (n1, n2, n3, n4)

a = 0x81233333   # 5.1
b = convert_long_to_bytes(a)

print (b)        # result: (129L, 35L, 51L, 51L)
``````

jahboater
Posts: 6512
Joined: Wed Feb 04, 2015 6:38 pm
Location: Wonderful West Dorset

Re: Conversion

You should use python3 integer division.

Code: Select all

``````def convert_long_to_bytes(i):
i %= 4294967296
n4 = i % 256
i //= 256
n3 = i % 256
i //= 256
return (i // 256, i % 256, n3, n4)
``````
I'm pretty sure its vastly more efficient, and simpler, than converting it all to floating-point, then rounding it, and finally truncating it back to an integer! Also I think the "round" call was unnecessary and probably wrong.

rpiMike
Posts: 1609
Joined: Fri Aug 10, 2012 12:38 pm
Location: Cumbria, UK

Re: Conversion

What about using the bitstring library?

Code: Select all

``````pip3 install bitstring
``````

Code: Select all

``````import bitstring
f1 = bitstring.BitArray(float=5.1, length=32)
print(f1.bin)``````
01000000101000110011001100110011

California
Posts: 201
Joined: Sat Jun 06, 2015 2:33 pm

Re: Conversion

@jahboater:
your lines of the code works ok, but not with the rest of the code lines.
The very same error as before:

Code: Select all

``````...
i %= 4294967296
TypeError: not all arguments converted during string formatting``````
@rpiMike:
described part of the code works ok, but yes, your solution looks much better than my... I'll try to use it

B.Goode
Posts: 10902
Joined: Mon Sep 01, 2014 4:03 pm
Location: UK

Re: Conversion

California wrote:
Sat Nov 09, 2019 6:43 pm
@jahboater:
your lines of the code works ok, but not with the rest of the code lines.
The very same error as before:

Code: Select all

``````...
i %= 4294967296
TypeError: not all arguments converted during string formatting``````
@rpiMike:
described part of the code works ok, but yes, your solution looks much better than my... I'll try to use it
Not really the same error, because the two lines of source code are different.

What does Python think is the type of the argument 'i' when you use it in your production code?

California
Posts: 201
Joined: Sat Jun 06, 2015 2:33 pm

Re: Conversion

In python 2 result is: (129L, 35L, 51L, 51L)
In python 3 result is: (129, 35, 51, 51)

As you can see, diference is in the letter L. Maybe this is what error message say.
So, how to get the letter L into result?

billio
Posts: 71
Joined: Thu Dec 15, 2011 8:25 am
Contact: Website

Re: Conversion

Python 2 has normal length integers and long integers, the latter being represented with a trailing L.

Code: Select all

``````>>> type(666L)
<type 'long'>
>>> type(666)
<type 'int'>
``````
I believe that is where the L comes from. But can I ask what the purpose of the function "def convert_long_to_bytes" is. If it is to convert python2 long integers to bytes then this doesn't seem necessary as python3 doesn't have long integers, just integers. Python3 has a function to convert integers to bytes ( https://docs.python.org/3/library/stdty ... ger-types ):

Code: Select all

``````>>> a = 666
>>> a.to_bytes(4,"big")
b'\x00\x00\x02\x9a'``````
However, your example is confusing me as it uses a floating point number ' # 5.1 ' .

California
Posts: 201
Joined: Sat Jun 06, 2015 2:33 pm

Re: Conversion

First of all, I want to thank all of you for your help here.
The purpose of this part of the code is converting temperature setpoint (float) into bytes on the Rpi3 which represents master in RS485 network.
Floating point number 5.1 is just an example, could be used any other positive or negative number.
This form of setpoint is thantransmitted over network to the slave (Microchip's PIC18F458), where is written into EEPROM ...

So, is there any other way to convert in python3 (for example) 0x81233333 into form (129, 35, 51, 51)

billio
Posts: 71
Joined: Thu Dec 15, 2011 8:25 am
Contact: Website

Re: Conversion

There may be a better way than this but :

Code: Select all

``````>>> a = 0x81233333
>>> b = a.to_bytes(4,"big",signed=False)
>>> c = [int(i) for i in b]
>>> c
[129, 35, 51, 51]
``````

rpiMike
Posts: 1609
Joined: Fri Aug 10, 2012 12:38 pm
Location: Cumbria, UK

Re: Conversion

Combining both gives the following, however I get different values for 5.1 - is your example correct?

Code: Select all

``````import bitstring
f=5.1
print(f)
ba = bitstring.BitArray(float=f, length=32)
print(ba.hex)
ih = int(ba.hex,16)
b = ih.to_bytes(4,"big",signed=False)
c = [int(i) for i in b]
print(c)``````
5.1
40a33333
[64, 163, 51, 51]

California
Posts: 201
Joined: Sat Jun 06, 2015 2:33 pm

Re: Conversion

@billio:
so far so god, it looks ok - I have to do more tests

@rpiMike:
your result is also ok, but it is coded in normal float 32 (IEEE) standard, for me it is used Microchip float 32 standard

California
Posts: 201
Joined: Sat Jun 06, 2015 2:33 pm

Re: Conversion

Thanks to all of you, code works as expected.

With best regards,