I'm trying to write a basic FP16 based calculator in python to help me debug some hardware. Can't seem to find how to convert 16b hex values unto floating point values I can use in my code to do the math. I see lots of online references to numpy but I think the float16 constructor expects a string like float16("1.2345"). I guess what I'm looking for is something like float16("0xabcd").
Thanks!
The numpy.float16 is indeed a signed floating point format with a 5-bit exponent and 10-bit mantissa.
To get the result of your example:
import numpy as np
np.frombuffer(b'\xab\xcd', dtype=np.float16, count=1)
Result:
array([-22.67], dtype=float16)
Or, to show how you can encode and decode the other example 1.2345:
import numpy as np
a = np.array([1.2345], numpy.float16)
b = a.tobytes()
print(b)
c = np.frombuffer(b, dtype=np.float16, count=1)
print(c)
Result:
b'\xf0<'
[1.234]
If you literally needed to turn the string you provided into an FP16:
import numpy as np
s = "0xabcd"
b = int("0xabcd", base=16).to_bytes(2, 'big')
print(b)
c = np.frombuffer(b, dtype=np.float16, count=1)
print(c)
Output:
b'\xab\xcd'
[-22.67]
Related
i have a problem in python3
my variable is
i = 31.807
I would transform in this:
i = 31.80
with two numbers after the decimal point and without round even show 0 in end.
Question: how do I round a float in Python to the desired decimal digit?
You can use numpy.round and supply the value to round and the number of significant digits, i.e.
import numpy as np
i = np.round(31.807, 2)
print(i)
the output is going to be 31.81, which differs from you example.
Question: how do I ceil/floor to the desired decimal digit?
Unfortunately numpy.ceil and numpy.floor do not allow for that, so you need to be a bit more crafy:
import numpy as np
i = np.floor(31.807*100)/100
print(i)
the output is now 31.8.
Question: how do I print a number in a specific format?
Here there is no single write way to go, one possibility is:
print("{:.2f}".format(31.8))
Output: 31.80.
I think the solution from this question here: stackoverflow.com/a/37697840/5273907 would solve your problem i.e.:
import math
def truncate(number, digits) -> float:
stepper = 10.0 ** digits
return math.trunc(stepper * number) / stepper
When I test it locally with your example I get:
>>> truncate(31.807, 2)
31.8
I'm looking for a way to neatly show rounded floats of varying decimal lengh.
Example of what I'm looking for:
In: 0.0000000071234%
Out: 0.0000000071%
In: 0.00061231999999%
Out: 0.0061%
In: 0.149999999%
Out: 0.15%
One way to do it would be:
def dynamic_round(num):
zeros = 2
original = num
while num< 0.1:
num*= 10
zeros += 1
return round(original, zeros)
I'm sure however there is a much cleaner way to do the same thing.
Here's a way to do it without a loop:
a = 0.003123
log10 = -int(math.log10(a))
res = round(a, log10+2)
==> 0.0031
This post answers your question with a similar logic
How can I format a decimal to always show 2 decimal places?
but just to clarify
One way would be to use round() function also mentioned in the documentation
built-in functions: round()
>>> round(number[,digits])
here digit refers to the precision after decimal point and is optional as well.
Alternatively, you can also use new format specifications
>>> from math import pi # pi ~ 3.141592653589793
>>> '{0:.2f}'.format(pi)
'3.14'
here the number next to f tells the precision and f refers to float.
Another way to go here is to import numpy
>>>import numpy
>>>a=0.0000327123
>>>res=-int(numpy.log10(a))
>>>round(a,res+2)
>>>0.000033
numpy.log() also, takes an array as an argument, so if you have multiple values you can iterate through the array.
I am fairly new to python is there a fast way to convert decimal to 16-bit fixed-point binary (1-bit sign – 7-bit integer – 8-bit fraction) and back in python.
I would like to manipulate the binary and convert this manipulated binary back to decimal.
Example 1.25 -> 00000001.01000000
Manipulate first fraction part (0->1)
00000001.11000000 -> 1.75
Would really appreciate any help.
If you have N bits in the fractional part then you just need to divide by 2N, since the stored bit pattern is actually the real value multiplied by 2N. Therefore with Q8.8 like in your case you'll have to divide by 256
For your 00000001.01000000 and 00000001.11000000 examples above:
>>> 0b0000000101000000/256.0
1.25
>>> 0b0000000111000000/256.0
1.75
You can use the Binary fractions package.
Example:
>>> from binary_fractions import Binary
>>> b = Binary(15.5)
>>> print(b)
0b1111.1
>>> Binary(1.25).lfill(8).rfill(8)
Binary(00000001.01000000, 0, False)
>>> Binary(1.75).lfill(8).rfill(8)
Binary(00000001.11000000, 0, False)
>>> Binary('0b01.110').lfill(8).rfill(8)
Binary(00000001.11000000, 0, False)
>>> Binary('0b01.110').lfill(8).rfill(8).string()
'00000001.11000000'
It has many more helper functions to manipulate binary strings such as: shift, add, fill, to_exponential, invert...
PS: Shameless plug, I'm the author of this package.
You can use fxpmath to do calculations simplier.
Info about fxpmath:
https://github.com/francof2a/fxpmath
Your example could be solved like:
from fxpmath import Fxp
x = Fxp(1.25, True, 16, 8) # signed=True, n_word=16, n_frac=8
x.bin(frac_dot=True)
out:
'00000001.01000000'
Now you can apply an OR mask to do 0 bit val to 1:
y = x | Fxp('0b01.110', True, 16, 8)
print(y.bin(frac_dot=True))
print(y)
out:
'00000001.11000000'
1.75
numfi can transform floating point number to fixed point with certain word/fraction length, but directly manipulate binary bits is not possible.
You can use bitwise logical operation like and/or/xor to modify bits as workaround, for computation heavy program, bitwise operation should be faster than string evaluation
>>> from numfi import numfi
>>> x = numfi(1.25,1,16,8)
>>> x
numfi([1.25]) s16/8-r/s
>>> x.bin
array(['0000000101000000'], dtype='<U16')
>>> x.bin_
array(['11111110.11000000'], dtype='<U17')
>>> y = x | 0b0000000010000000
>>> y
numfi([1.75]) s16/8-r/s
>>> y.bin_
array(['00000001.11000000'], dtype='<U17')
I have around ten variables (variables / arrays / symmetric matrices) which i want to get through an url. Because i will use a a rest api there is a limit on the size of the url so i need to encode it in a string of minimal length and encrypt. Any idea ? I've always supposed that's how google or other website transmit information sometimes when the adress is downright initelligible
My original idea was to encode all numbers in scientific notation and use separators (2.4e14__3.1e12_2.5e10_ for example to pass a number 2.4e14 and a array [3.1e12_2.5e10]) and encode this string. Possibly use another base (base with numbers + letters) for futher concatenation but i'm not sure how i can save so much string space.
Maybe there's an existing library or technique ? i didn't find it.
Pickle and base64 will do the job nicely. Your floating point numbers remain as binary, not converted through ascii.
>>> import numpy as np
>>> a = np.array([0,1,2])
>>> import pickle
>>> import base64
>>> b64 = base64.b64encode(pickle.dumps(a))
At the other end
>>> n = pickle.loads(base64.b64decode(b64))
>>> print(n)
array([0, 1, 2])
However, this won't be the shortest representation possible. Sufficient information to fully reconstruct the object is transmitted. If it is short enough it is the most easily extended and modified option.
You can convert a numpy object to python list.Then convert list to a json string.
>>> import numpy as np
>>> import json
>>> a = np.array([0,1,2])
>>> b = a.tolist()
>>> c = json.dumps(b)
Similarly,you can convert json string to numpy by: json string->list->numpy
>>> d = np.array(json.loads(c))
How to convert floating point number to base-16 numbers, 8 hexadecimal digits per 32-bit FLP number in python?
eg : input = 1.2717441261e+20 output wanted : 3403244E
If you want the byte values of the IEEE-754 representation, the struct module can do this:
>>> import struct
>>> f = 1.2717441261e+20
>>> struct.pack('f', f)
'\xc9\x9c\xdc`'
This is a string version of the bytes, which can then be converted into a string representation of the hex values:
>>> struct.pack('f', f).encode('hex')
'c99cdc60'
And, if you want it as a hex integer, parse it as such:
>>> s = struct.pack('f', f).encode('hex')
>>> int(s, 16)
3382500448
To display the integer as hex:
>>> hex(int(s, 16))
'0xc99cdc60'
Note that this does not match the hex value in your question -- if your value is the correct one you want, please update the question to say how it is derived.
There are several possible ways to do so, but none of them leads to the result you wanted.
You can code this float value into its IEEE binary representation. This leads indeed to a 32 bit number (if you do it with single precision). But it leads to different results, no matter which endianness I suppose:
import struct
struct.pack("<f", 1.2717441261e+20).encode("hex")
# -> 'c99cdc60'
struct.pack(">f", 1.2717441261e+20).encode("hex")
# -> '60dc9cc9'
struct.unpack("<f", "3403244E".decode("hex"))
# -> (687918336.0,)
struct.unpack(">f", "3403244E".decode("hex"))
# -> (1.2213533295835077e-07,)
As the other one didn't fit result-wise, I'll take the other answers and include them here:
float.hex(1.2717441261e+20)
# -> '0x1.b939919e12808p+66'
Has nothing to do with 3403244E as well, so maybe you want to clarify what exactly you mean.
There are surely other ways to do this conversation, but unless you specify which method you want, no one is likely to be able to help you.
There is something wrong with your expected output :
import struct
input = 1.2717441261e+20
buf = struct.pack(">f", input)
print ''.join("%x" % ord(c) for c in struct.unpack(">4c", buf) )
Output :
60dc9cc9
Try float.hex(input) if input is already a float.
Try float.hex(input). This should convert a number into a string representing the number in base 16, and works with floats, unlike hex(). The string will begin with 0x however, and will contain 13 digits after the decimal point, so I can't help you with the 8 digits part.
Source: http://docs.python.org/2/library/stdtypes.html#float.hex