Lucian Lucian - 23 days ago 7
Python Question

Integer to Float thorws TypeError: Non-hexadecimal digit found



I am trying to convert a float number to long and back just to see how to send it via sockets. I made the FloatToInt method just to test that number that I can't deserialize.

When converting it from float to long it works fine, but when I try to convert it from long to float again it throws "Non-hex digit found"

def FloatToInt(num):
num = 22083.60066068796
print "FloatToInt:float:%.10f" %num
packed = struct.pack('!f', num)
print 'FloatToInt:Packed: %s' % repr(packed)
integers = [ord(c) for c in packed]
print 'FloatToInt:Integers: %s' % repr(integers)
val = int(0)
for i in integers:
val |= i
val = val << 8
return val

def IntToFloat(num):
#val = struct.unpack('!f', num.decode('hex'))[0]
#return val
intArr = []
while num > 0:
val = num & 0xFF
if val > 0:
intArr.append(int(val))
num = num >> 8
print 'IntToFloat:Integers: %s' % repr(intArr)
chars = [chr(c) for c in intArr]
str = ""
for ch in chars:
str += ch
print 'IntToFloat:Hex chars: %s' % repr(str)
ret = struct.unpack('!f', str.decode('hex'))[0]
return ret


This outputs:


FloatToInt:float:22083.6006606880

FloatToInt:Packed: 'F\xac\x874'

FloatToInt:Integers: [70, 172, 135, 52]


IntToFloat:Integers: [52, 135, 172, 70]

IntToFloat:Hex chars: '4\x87\xacF'


Traceback (most recent call last):

........

TypeError: Non-hexadecimal digit found


So str.decode('hex') throws an error, although I have the same integer values as when I packed the values in the FloatToInt method.

Do you have any ideea what I'm missing?

Thank you

Answer

decode('hex') is use to decode strings like this '0487AC0F'.

print( '0487AC0F'.decode('hex') )

But you don't need decode() in your code. You have to only reverse elements in intArr to get correct result.

BTW. to send float via socket you need only pack/unpack - you don't have to create long int - because socket can send only string or rather bytes. To send long int via socket you will need pack/unpack to convert it into string/bytes.

import struct

def FloatToInt(num):
    num = 22083.60066068796
    print "FloatToInt:float:%.10f" %num

    packed = struct.pack('!f', num)
    print 'FloatToInt:Packed: %s' % repr(packed)

    integers = [ord(c) for c in packed]
    print 'FloatToInt:Integers: %s' % repr(integers)

    val = int(0)
    for i in integers:
        val |= i
        val = val << 8

    return val

def IntToFloat(num):
    intArr = []

    while num > 0:
        val = num & 0xFF
        if val > 0:
            intArr.append(val)
        num = num >> 8

    # you have to reverse numbers
    intArr = list(reversed(intArr))

    print 'IntToFloat:Integers: %s' % repr(intArr)

    text = "".join([chr(c) for c in intArr])
    #chars = [chr(c) for c in intArr]
    #text = ""
    #for ch in chars:
    #    text += ch

    print 'IntToFloat:Hex chars: %s' % repr(text)

    # you don't need decode('hex')
    ret = struct.unpack('!f', text)[0]

    return ret

num = 22083.60066068796
r = FloatToInt(num)
print '   FloatToInt:', r 
r = IntToFloat(r) 
print '   IntToFloat:', r

EDIT: Python uses CPU float but it has two types

  • single precision - called "float"
  • double precision - called "double"

It seams Python use "double" in this example so you can use !d instead of !f to get correct value

import struct

num = 22083.60066068796
print "   float: %.10f" % num

packed = struct.pack('!d', num)
print '  packed: %s' % repr(packed)

ret = struct.unpack('!d', packed)[0]
print "unpacked: %.10f" %num

.

   float: 22083.6006606880
  packed: '@\xd5\x90\xe6q9\x86\xb2'
unpacked: 22083.6006606880

"double" in previous code

 import struct

def FloatToInt(num):

    print "FloatToInt:    float: %.10f" % num

    packed = struct.pack('!d', num)
    print 'FloatToInt:   Packed: %s' % repr(packed)

    integers = [ord(c) for c in packed]
    print 'FloatToInt: Integers: %s' % integers

    val = int(0)
    for i in integers:
        val |= i
        val = val << 8

    print 'FloatToInt:   result: %d\n' % val

    return val

def IntToFloat(num):

    print 'IntToFloat:  integer: %d\n' % num

    intArr = []

    while num > 0:
        val = num & 0xFF
        if val > 0:
            intArr.append(val)
        num = num >> 8

    intArr = list(reversed(intArr))

    print 'IntToFloat: Integers: %s' % intArr

    text = "".join([chr(c) for c in intArr])
    print 'IntToFloat:Hex chars: %s' % repr(text)

    ret = struct.unpack('!d', text)[0]
    print 'IntToFloat:   result: %.10f\n' % ret

    return ret

num = 22083.60066068796
r = FloatToInt(num)
r = IntToFloat(r)

.

FloatToInt:    float: 22083.6006606880
FloatToInt:   Packed: '@\xd5\x90\xe6q9\x86\xb2'
FloatToInt: Integers: [64, 213, 144, 230, 113, 57, 134, 178]
FloatToInt:   result: 1195980674018107109888

IntToFloat:  integer: 1195980674018107109888
IntToFloat: Integers: [64L, 213L, 144L, 230L, 113L, 57L, 134L, 178L]
IntToFloat:Hex chars: '@\xd5\x90\xe6q9\x86\xb2'
IntToFloat:   result: 22083.6006606880