struct.unpack with precision after decimal points - python

I am reading data from a binary file, it contains floating point data of which I want only first 6 digits after decimal point but its printing a pretty long string.
self.dataArray.append(struct.unpack("f", buf)[0])
I tried with this
self.dataArray.append(struct.unpack(".6f", buf)[0])
But it didn't worked.
Thanks in advance

a float isnt a string and a string isnt a float.
all a float is, is a number of bytes interpreted as both a whole number part and a fractional part
the_float = struct.unpack("f", buf)[0]
print "The Float String %0.6f"%(the_float)

Related

Large decimal numbers with function math.modf

I am using the function math.modf which separates the integer and decimal part of a number as follows:
decimal_part, integer_part = math.modf(x)
Where x is a decimal number.
An example for a small number is as follows:
x = 1993.0787353515625
decimal_part = 0.0787353515625, integer_part = 1993.0
But when I work with very large numbers the following happens:
x = 6.797731511223558e+44
decimal_part = 0.0, integer_part = 6.797731511223558e+44
In this case it doesn't save the result in the decimal part and appears 0.0. And the same happens for numbers up to 300 digits. But when the number x has at least 360 digits, the following error appears:
OverflowError: int too large to convert to float.
I would like to save the decimal part of large numbers of at least 300 digits without overflowing the register where the decimal part is stored. And I would like to avoid the error in numbers with more than 360 digits: "OverflowError: int too large to convert to float".
How can I solve it?
Due to the extra information it has to save, float needs more space than int. But let's break this down:
The number 6.797731511223558e+44 is an integer, which means it has no decimal part, so it will always return 0.0 as decimal.
If you are providing an integer with 300+ digits, it will still be an integer, so the decimal part will still be 0.0, so there's no need to use the function. You are getting that error because you are passing a very large int that is converted to float to give you the result, but this is not necessary since you already know the result.
On the other hand, if you use the function with a float, the function doesn't have problems casting float to float, so it won't show the error.
The number 6.797731511223558e+44 should be a number with a decimal part because it is the result of dividing a number by another number. But python doesn't save the decimal result and 0.0 appears. When we introduce small numbers in the function, it saves the decimal part.

Clean way to convert string to floating point number with specific precision?

I'm trying to convert strings of numbers that come from the output of another program into floating point numbers with two forced decimal places (including trailing zeros).
Right now I'm converting the strings to floats, then separately specifying precision (two decimal places), then converting back to float to do numeral comparisons on later.
# convert to float
float1 = float(output_string[6])
# this doesn't guarantee two decimal places in my output
# eg: -36.55, -36.55, -40.34, -36.55, -35.7 (no trailing zero on the last number)
nice_float = float('{0:.2f}'.format(float1))
# this works but then I later need to convert back into a float
# string->float->string->float is not super clean
nice_string = '{0:.2f}'.format(float1)
Edit for clarity:
I have a problem with the display in that I need that to show exactly two decimal places.
Is there a way to convert a string to a floating point number rounded to two decimal places that's cleaner than my implementation which involves converting a string to a float, then the float back into a formatted string?

How to convert HEX string to Float (Little Endian)

I just learned Python (3.x) and I am stuck with HEX String conversion to Float. I have this HEX String values:
'0x22354942F31AFA42CE6A494311518A43082CAF437C6BD4C35F78FA433BF10F442A5222448D3D3544200749C438295C4468AF6E4406B4804450518A4423B0934450E99CC4'
And I want to turn it into float.
I have tried to use this code:
bs=bytes.fromhex(row[2:])
fmt = '<' + ('H' * (len(bs) // 2))
res=struct.unpack(fmt, bs)
and it gives me the result of 13602.0,16969.0,6899.0,17146.0,27342.0,17225.0,20753.0,17290.0,11272.0,17327.0,27516.0,50132.0,30815.0,17402.0,61755.0,17423.0,21034.0,17442.0,15757.0,17461.0,1824.0,50249.0,10552.0,17500.0,44904.0,17518.0,46086.0,17536.0,20816.0,17546.0,45091.0,17555.0,59728.0,50332.0
After checking it, I found out that the code that what I currently have is float in base 16, while I need it in base 32 (or maybe not because I am not sure what base/format), with expected float results as 50.3018875, 125.052635,201.4172,276.633331,350.344,424.839722,500.9404,575.7692,649.2838,724.961731,804.1113,880.644043,954.7407,1029.62573,106.541,1181.50427,1255.291 the values which I got from this Calculator Converter.
What should I change in the coding to get the expected results?
Thank you.
Let's break things down here, because you seem to be confused a bit with all of the juggling of representations. You have some hexadecimal string (that's base 16 encoding) of some binary data. That's your 0x22354942F31AFA42CE6A494311.... You correctly identified that you can convert this from its encoded form to python bytes with bytes.fromhex:
hex_encoded = '0x22354942F31AFA42CE6A494311518A43082CAF437C6BD4C35F78FA433BF10F442A5222448D3D3544200749C438295C4468AF6E4406B4804450518A4423B0934450E99CC4'
binary_data = bytes.fromhex(hex_encoded[2:]) # we do 2: to remove the leading '0x'
At this point, unless we know how binary_data was constructed we can't do anything. But we can take some guesses. You know the first few numbers are floating points: 50.3018875, 125.052635, 201.4172, .... Typically floats are encoded using the IEEE 754 standard. This provides 3 different encodings of a floating point number: binary16 (16 bits), float (32 bits), and double (64 bits). You can see these in the struct documentation, they are format codes 'e', 'f', and 'd', respectively. We can try each to see which of (if any) your binary data is encoded as. By trial and error, we discover your data was encoded as 32-bit floats, so you can decode them with:
FLOAT = 'f'
fmt = '<' + FLOAT * (len(binary_data) // struct.calcsize(FLOAT))
numbers = struct.unpack(fmt, binary_data)
print(numbers)
Why did what you tried not work? Well you used the format code 'H' which is for an unsigned short. This is an integer, which is why you were getting back numbers with no fractional part!

How to convert hex to IEEE floating point python

I want to convert this hex string '8436d4ccd436d3333' to IEEE floating point. I've try to do this with struct.unpack but it's requires a string argument of length 4.
struct.unpack('>f', binascii.unhexlify('8436d999a436e0000'))
I'm using this website to verify if my conversion attempts are correct : https://gregstoll.dyndns.org/~gregstoll/floattohex/ but I can't find a way to do this.
Thanks for any help
At a guess, each hex string contains two single-precision floating-point values, not one, and the initial 8 is part of the whatever message protocol is being used, and not a part of either of those floats. With that guess, I get some plausible-looking numbers:
>>> struct.unpack('>ff', binascii.unhexlify('436d4ccd436d3333'))
(237.3000030517578, 237.1999969482422)
>>> struct.unpack('>ff', binascii.unhexlify('436d999a436e0000'))
(237.60000610351562, 238.0)
And to reinforce the plausibility, here's what I get by encoding the corresponding 1-digit-past-the-decimal-point values:
>>> binascii.hexlify(struct.pack('>ff', 237.3, 237.2))
b'436d4ccd436d3333'
>>> binascii.hexlify(struct.pack('>ff', 237.6, 238.0))
b'436d999a436e0000'

Convert scientific notation string into int

How would I convert:
s='8.833167174e+11' (str)
==> 883316717400 (int)
I tried doing int(s) or some other 'casting' but it wasn't effective.
As your string is a float digit you need to first convert it to float:
>>> int(float(s))
883316717400
float([x])
Return a floating point number constructed from a number or string x.
If the argument is a string, it must contain a possibly signed decimal or floating point number, possibly embedded in whitespace. The argument may also be [+|-]nan or [+|-]inf. Otherwise, the argument may be a plain or long integer or a floating point number, and a floating point number with the same value (within Python’s floating point precision) is returned. If no argument is given, returns 0.0.

Categories