我想知道如何将float.hex()
返回的结果转换为二进制,例如,从0x1.a000000000000p+2
转换为110.1
。
有人可以帮忙吗?感谢。
答案 0 :(得分:10)
def float_to_binary(num):
exponent=0
shifted_num=num
while shifted_num != int(shifted_num):
shifted_num*=2
exponent+=1
if exponent==0:
return '{0:0b}'.format(int(shifted_num))
binary='{0:0{1}b}'.format(int(shifted_num),exponent+1)
integer_part=binary[:-exponent]
fractional_part=binary[-exponent:].rstrip('0')
return '{0}.{1}'.format(integer_part,fractional_part)
def floathex_to_binary(floathex):
num = float.fromhex(floathex)
return float_to_binary(num)
print(floathex_to_binary('0x1.a000000000000p+2'))
# 110.1
print(floathex_to_binary('0x1.b5c2000000000p+1'))
# 11.01101011100001
<强>解释强>:
float.fromhex
返回一个浮动num
。我们想要它的二进制表示。
{0:b}.format(...)
返回整数的二进制表示,但不返回浮点数。
但是如果我们将浮点乘以2的足够幂,即将二进制表示移到左侧足够的位置,我们最终得到一个整数shifted_num
。
一旦我们有了这个整数,我们就可以免费回家,因为现在我们可以使用{0:b}.format(...)
。
我们可以根据我们向左移动的位置(exponent
)使用一些字符串切片重新插入小数点(错误,二进制点?)。
技术要点:shifted_num
的二进制表示中的位数可能小于exponent
。在这种情况下,我们需要在左侧填充更多0的二进制表示,因此使用binary[:-exponent]
的二进制切片不会为空。我们使用'{0:0{1}b}'.format(...)
进行管理。格式字符串中的0{1}
将格式化字符串的宽度设置为{1}
,在左侧用零填充。 ({1}
会被数字exponent
取代。)
答案 1 :(得分:3)
注意,0x1.a000000000000p+2
的二进制格式不是101.1
(或更确切地说是0b101.1
)
但0b110.1
(在我的Python 2.7中,二进制数字显示如此)
第一个,一个有用的浮点实例float.hex()
方法及其反函数,一个浮点类方法float.fromhex()
fh = 12.34.hex()
print fh
print float.fromhex(fh)
结果
0x1.8ae147ae147aep+3 # hexadecimal representation of a float
12.34
“请注意,float.hex()是一个实例方法,而float.fromhex()是一个类方法。”
http://docs.python.org/library/stdtypes.html#float.fromhex
其次,我没有找到一个Python的函数来将float的十六进制表示转换为这个float的二进制表示,也就是说用一个点(也不是一个直接转换) float的十进制表示形式为二进制表示。)
所以我为此创建了一个函数。
在此之前,此函数将十六进制表示转换为输入float的十进制表示(字符串)。
然后有两个问题:
如何在点之前转换部分?
这部分是一个整数,很容易使用bin()
如何在点后转换部分? 在SO上已经多次询问过这种转换的问题,但我不理解这些解决方案,所以我自己写了。
然后,这是你想要的功能,李强:
def hexf2binf(x):
'''Transforms an hexadecimal float with a dot into a binary float with a dot'''
a,_,p = str(float.fromhex(x)).partition('.')
# the following part transforms the part after the dot into a binary after the dot
tinies = [ Decimal(1) / Decimal(2**i) for i in xrange(1,400)]
bits = []
pdec = Decimal('.'+p)
for tin in tinies:
if pdec-tin==0:
bits.append('1')
break
elif pdec-tin>0:
bits.append('1')
pdec -= tin
else:
bits.append('0')
pbin = ''.join(bits) # it's the binary after the dot
# the integer before the dot is easily transformed into a binary
return '.'.join((bin(int(a)),pbin))
为了执行验证,我写了一个函数来将一个点之后的二进制浮点的一部分转换为十进制表示:
from decimal import Decimal, getcontext()
getcontext().prec = 500
# precision == 500 , to be large !
tinies = [ Decimal(1) / Decimal(2**i) for i in xrange(1,400)]
com = dict((i,tin) for i,tin in enumerate(tinies,1))
def afterdotbinary2float(sbin, com = com):
'''Transforms a binary lying after a dot into a float after a dot'''
if sbin.startswith('0b.') or sbin.startswith('.'):
sbin = sbin.split('.')[1]
if all(c in '01' for c in sbin):
return sum(int(c)*com[i] for i,c in enumerate(sbin,1))
else:
return None
最后,应用以下功能:
from decimal import Decimal
getcontext().prec = 500
# precision == 500 , to be large !
tinies = [ Decimal(1) / Decimal(2**i) for i in xrange(1,400)]
com = dict((i,tin) for i,tin in enumerate(tinies,1))
def afterdotbinary2float(sbin, com = com):
'''Transforms a binary lying after a dot into a float after a dot'''
if sbin.startswith('0b.') or sbin.startswith('.'):
sbin = sbin.split('.')[1]
if all(c in '01' for c in sbin):
return sum(int(c)*com[i] for i,c in enumerate(sbin,1))
else:
return None
def hexf2binf(x):
'''Transforms an hexadecimal float with a dot into a binary float with a dot'''
a,_,p = str(float.fromhex(x)).partition('.')
# the following part transforms the float after the dot into a binary after the dot
tinies = [ Decimal(1) / Decimal(2**i) for i in xrange(1,400)]
bits = []
pdec = Decimal('.'+p)
for tin in tinies:
if pdec-tin==0:
bits.append('1')
break
elif pdec-tin>0:
bits.append('1')
pdec -= tin
else:
bits.append('0')
pbin = ''.join(bits) # it's the binary after the dot
# the float before the dot is easily transformed into a binary
return '.'.join((bin(int(a)),pbin))
for n in (45.625 , 780.2265625 , 1022.796875):
print 'n ==',n,' transformed with its method hex() to:'
nhexed = n.hex()
print 'nhexed = n.hex() ==',nhexed
print '\nhexf2binf(nhexed) ==',hexf2binf(nhexed)
print "\nVerification:\nbefore,_,after = hexf2binf(nhexed).partition('.')"
before,_,after = hexf2binf(nhexed).partition('.')
print 'before ==',before,' after ==',after
print 'int(before,2) ==',int(before,2)
print 'afterdotbinary2float(after) ==',afterdotbinary2float(after)
print '\n---------------------------------------------------------------\n'
结果
n == 45.625 transformed with its method hex() to:
nhexed = n.hex() == 0x1.6d00000000000p+5
hexf2binf(nhexed) == 0b101101.101
Verification:
before,_,after = hexf2binf(nhexed).partition('.')
before == 0b101101 after == 101
int(before,2) == 45
afterdotbinary2float(after) == 0.625
---------------------------------------------------------------
n == 780.2265625 transformed with its method hex() to:
nhexed = n.hex() == 0x1.861d000000000p+9
hexf2binf(nhexed) == 0b1100001100.0011101
Verification:
before,_,after = hexf2binf(nhexed).partition('.')
before == 0b1100001100 after == 0011101
int(before,2) == 780
afterdotbinary2float(after) == 0.2265625
---------------------------------------------------------------
n == 1022.796875 transformed with its method hex() to:
nhexed = n.hex() == 0x1.ff66000000000p+9
hexf2binf(nhexed) == 0b1111111110.110011
Verification:
before,_,after = hexf2binf(nhexed).partition('.')
before == 0b1111111110 after == 110011
int(before,2) == 1022
afterdotbinary2float(after) == 0.796875
---------------------------------------------------------------
对于两个数字:
from decimal import Decimal
tinies = [ Decimal(1) / Decimal(2**i) for i in xrange(1,400)]
com = dict((i,tin) for i,tin in enumerate(tinies,1))
def hexf2binf(x, tinies = tinies):
'''Transforms an hexadecimal float with a dot into a binary float with a dot'''
a,_,p = str(float.fromhex(x)).partition('.')
# the following part transforms the float after the dot into a binary after the dot
bits = []
pdec = Decimal('.'+p)
for tin in tinies:
if pdec-tin==0:
bits.append('1')
break
elif pdec-tin>0:
bits.append('1')
pdec -= tin
else:
bits.append('0')
pbin = ''.join(bits) # it's the binary after the dot
# the float before the dot is easily transformed into a binary
return '.'.join((bin(int(a)),pbin))
print hexf2binf('0x1.a000000000000p+2')
print
print hexf2binf('0x1.b5c2000000000p+1')
结果显示:
0b110.1
0b11.011010111000010000000000000000000000010000011111100001111111101001000110110000101101110000000001111110011100110101011100011110011101111010001011111001011101011000000011001111111010111011000101000111100100110000010110001000111010111101110111011111000100100110110101011100101001110011000100000000010001101111111010001110100100101110111000111111001011101101010011011111011001010011111111010101011010110
答案 2 :(得分:1)
给定十六进制字符串h
,您可以找到带有
x = float.fromhex(h)
所以你真的很有兴趣能够产生任何浮点数的“定点”二进制表示。它可能没有有限的表示,所以你可能想限制它的长度。 (例如,math.pi的二进制表示不会结束......)
以下内容可能会起作用
def binaryRepresentation(x, n=8):
# the base and remainder ... handle negatives as well ...
base = int(x)
fraction = abs(int(round( (x - base) * (2**n) )))
# format and remove redundant zeros
return "{0:b}.{1:b}".format(base, fraction).rstrip("0")
答案 3 :(得分:1)
大编辑关于大数字
以下代码在我的其他答案中显示了我的解决方案的问题 请注意,我将函数 hexf2binf(floathex)的参数从 h 更改为 floathex ,使其与<使用的参数相同em> unutbu 在他的函数中 floathex_to_binary(floathex)
from decimal import Decimal,getcontext
getcontext.prec = 500
tinies = [ Decimal(1) / Decimal(2**i) for i in xrange(1,400)]
com = dict((i,tin) for i,tin in enumerate(tinies,1))
def hexf2binf(floathex, tinies = tinies):
fromh = float.fromhex(floathex)
print 'fromh = float.fromhex(h) DONE'
print 'fromh ==',fromh
print "str(float.fromhex(floathex)) ==",str(float.fromhex(floathex))
a,_,p = str(float.fromhex(floathex)).partition('.')
print 'before the dot ==',a
print 'after the dot ==',p
# the following part transforms the float after the dot into a binary after the dot
bits = []
pdec = Decimal('.'+p)
for tin in tinies:
if pdec-tin==0:
bits.append('1')
break
elif pdec-tin>0:
bits.append('1')
pdec -= tin
else:
bits.append('0')
pbin = ''.join(bits) # it's the binary after the dot
# the float before the dot is easily transformed into a binary
return '.'.join((bin(int(a)),pbin))
x = x = 123456789012345685803008.0
print ' x = {:f}'.format(x)
h = x.hex()
print ' h = x.hex() ==',h
print '\nENTERING hexf2binf(floathex) with h as argument'
v = hexf2binf(h)
print '\nhexf2binf(x)==',v
结果
x = 123456789012345685803008.000000
h = x.hex() == 0x1.a249b1f10a06dp+76
ENTERING hexf2binf(floathex) with h as argument
fromh = float.fromhex(h) DONE
fromh == 1.23456789012e+23
str(float.fromhex(floathex)) == 1.23456789012e+23
before the dot == 1
after the dot == 23456789012e+23
hexf2binf(x)== 0b1.111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
问题是由于指令str(float.fromhex(x))
中的指令a,_,p = str(float.fromhex(x)).partition('.')
导致了一个带有指数的 float.fromhex(x)的表示。 。
然后在点之前的部分(a作为赌注)和点之后(作为帖子)是假的。
纠正这一点很简单:用这个替换不准确的指令:
a,_,p = '{:f}'.format(float.fromhex(x)).partition('.')
在运行Python的典型机器上,有53位精度 可用于Python浮点数,因此当您在内部存储该值 输入十进制数0.1是二进制分数 0.00011001100110011001100110011001100110011001100110011010 http://docs.python.org/tutorial/floatingpoint.html
这意味着当代码中写入float的大值时,其内部表示实际上是写入值的近似值。
这由以下代码显示:
x1 = 123456789012345685803008.0
print 'x1 == 123456789012345685803008.0'
h1 = x1.hex()
print 'h1 = x1.hex() ==',h1
y1 = float.fromhex(h1)
print 'y1 = float.fromhex(h1) == {:f}'.format(y1)
print
x2 = 123456789012345678901234.64655
print 'x2 == 123456789012345678901234.64655'
h2 = x2.hex()
print 'h2 = x2.hex() ==',h2
y2 = float.fromhex(h2)
print 'y2 = float.fromhex(h2) == {:f}'.format(y2)
print
结果
x1 == 123456789012345685803008.0
h1 = x1.hex() == 0x1.a249b1f10a06dp+76
y1 = float.fromhex(h1) == 123456789012345685803008.000000
x2 == 123456789012345678901234.64655
h2 = x2.hex() == 0x1.a249b1f10a06dp+76
y2 = float.fromhex(h2) == 123456789012345685803008.000000
h1 和 h2 的值相同,因为虽然为标识符 x1 和 x2 在脚本中,OBJECTS x1 和 x2 在机器中用相同的近似值表示。
123456789012345685803008.0 的内部表示是 123456789012345685803008.0 的确切值,并且是 123456789012345678901234.64655 的内部表示,但其近似值因此扣除 h1来自 x1 和 x2 的和 h2 为 h1 和 h2 <提供相同的值/强>
当我们在脚本中以十进制表示形式编号时,存在此问题。当我们以十六进制或二进制表示直接编写数字时,它不存在。
是我写了一个函数 afterdotbinary2float(sbin,com = com)来对 hexf2binf()产生的结果进行验证。当传递给 hexf2binf()的数字不大时,这个验证效果很好,但是由于大数字的内部近似(=有很多数字),我想知道这个验证是不是扭曲。实际上,当一个大数字到达函数时,它已经被近似:点后面的数字被转换成一系列零;
如下所示:
from decimal import Decimal, getcontext
getcontext().prec = 500
tinies = [ Decimal(1) / Decimal(2**i) for i in xrange(1,400)]
com = dict((i,tin) for i,tin in enumerate(tinies,1))
def afterdotbinary2float(sbin, com = com):
'''Transforms a binary lying after a dot into a float after a dot'''
if sbin.startswith('0b.') or sbin.startswith('.'):
sbin = sbin.split('.')[1]
if all(c in '01' for c in sbin):
return sum(int(c)*com[i] for i,c in enumerate(sbin,1))
else:
return None
def hexf2binf(floathex, tinies = tinies):
'''Transforms an hexadecimal float with a dot into a binary float with a dot'''
a,_,p = '{:.400f}'.format(float.fromhex(floathex)).partition('.')
# the following part transforms the float after the dot into a binary after the dot
bits = []
pdec = Decimal('.'+p)
for tin in tinies:
if pdec-tin==0:
bits.append('1')
break
elif pdec-tin>0:
bits.append('1')
pdec -= tin
else:
bits.append('0')
pbin = ''.join(bits) # it's the binary after the dot
# the float before the dot is easily transformed into a binary
return '.'.join((bin(int(a)),pbin))
for n in (123456789012345685803008.0, 123456789012345678901234.64655, Decimal('123456789012345.2546') ):
print 'n == {:f} transformed with its method hex() to:'.format(n)
nhexed = n.hex()
print 'nhexed = n.hex() ==',nhexed
print '\nhexf2binf(nhexed) ==',hexf2binf(nhexed)
print "\nVerification:\nbefore,_,after = hexf2binf(nhexed).partition('.')"
before,_,after = hexf2binf(nhexed).partition('.')
print 'before ==',before,' after ==',after
print 'int(before,2) ==',int(before,2)
print 'afterdotbinary2float(after) ==',afterdotbinary2float(after)
print '\n---------------------------------------------------------------\n'
结果
n == 123456789012345685803008.000000 transformed with its method hex() to:
nhexed = n.hex() == 0x1.a249b1f10a06dp+76
hexf2binf(nhexed) == 0b11010001001001001101100011111000100001010000001101101000000000000000000000000.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Verification:
before,_,after = hexf2binf(nhexed).partition('.')
before == 0b11010001001001001101100011111000100001010000001101101000000000000000000000000 after == 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
int(before,2) == 123456789012345685803008
afterdotbinary2float(after) == 0E-399
---------------------------------------------------------------
n == 123456789012345685803008.000000 transformed with its method hex() to:
nhexed = n.hex() == 0x1.a249b1f10a06dp+76
hexf2binf(nhexed) == 0b11010001001001001101100011111000100001010000001101101000000000000000000000000.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Verification:
before,_,after = hexf2binf(nhexed).partition('.')
before == 0b11010001001001001101100011111000100001010000001101101000000000000000000000000 after == 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
int(before,2) == 123456789012345685803008
afterdotbinary2float(after) == 0E-399
---------------------------------------------------------------
n == 123456789012345.2546 transformed with its method hex() to:
Traceback (most recent call last):
File "I:\verfitruc.py", line 41, in <module>
nhexed = n.hex()
AttributeError: 'Decimal' object has no attribute 'hex'
结论:使用数字 123456789012345685803008.0 和 123456789012345678901234.64655 进行测试没有任何区别,也没有兴趣。
所以,我想测试非近似数字,并且我传递了一个Decimal浮点数。如您所见,问题是这样的实例没有 hex()方法。
最后,我并不完全确定我的大数字功能,但在纠正不准确的指令后,它对于常用数字是正常的。
我在说明中添加了“.400”:
a,_,p = '{:.400f}'.format(fromh).partition('.')
否则 p 的值可能被截断,因此给出的二进制表示形式与传递给函数的数字略有不同。
我放400,因为它是我为列表 tinies 定义的长度,包含对应于1 / 2,1 / 4,1 / 8,1 / 16等的十进制实例
然而,虽然逗号之后的数字超过400位的数字很少有意义,但这种添加对我来说仍然不能令人满意:代码并不是绝对一般的,这是 unutbu的情况的代码。