Python中二进制和浮点类型互转
因为有某些需求需要修改float类型的二进制位数,但是发现float32无法直接进行位运算,所以通过学习一些基本的float机器表示方法来自己写了用来转化的一些功能函数。
参考:https://zhuanlan.zhihu.com/p/137616403
float转二进制
#整数部分计算
def int_bin(num):
ans = ''
while num != 0:
ans += str(num&1)
num = num >> 1
return ans[::-1]
#小数部分计算
def decimal_bin(num,bit_cnt=24):
ans = ''
while num != 0 and len(ans) < bit_cnt:
tmp = int(num*2)
ans += str(tmp)
num = num*2 - tmp
return ans
#指数部分计算
def exp_bin(exp,bit_cnt = 8):
ans = ''
while exp != 0:
ans += str(exp&1)
exp = exp >> 1
while len(ans) != bit_cnt:
ans += str(0)
return ans[::-1]
#计算float32转二进制表示,返回结果为string类型,32位
def float32_bin(num):
if num == 0:
return '0'*32
sign = 1
if num>0:
sign = 0 #符号位为1
int_par = int_bin(int(num))
decimal_par = decimal_bin(num - int(num))
exp = len(int_par) - 1 + 127 #获取阶码位数,需要让整数位为1
if len(int_par) == 0:
dot_pos = decimal_par.find('1') + 1 #没有整数部分,小数要找到对应的1
exp -= dot_pos - 1 #减的1是为了上面减的1,有整数部分的和没有的不同
decimal_par = decimal_par[dot_pos:]
base = int_par[1:] + decimal_par
while len(base) < 23: #一共23位尾数位补齐
base += str(0)
exp_par = exp_bin(exp)
ans = str(sign) + exp_par + base
return ans[:32]
#计算float64转二进制表示,返回结果为string类型,64位
def float64_bin(num):
if num == 0:
return '0'*64
sign = 1
if num>0:
sign = 0 #符号位为1
int_par = int_bin(int(num))
decimal_par = decimal_bin(num - int(num),bit_cnt=52)
exp = len(int_par) - 1 + 1023 #获取阶码位数,需要让整数位为1
if len(int_par) == 0:
dot_pos = decimal_par.find('1') + 1 #没有整数部分,小数要找到对应的1
exp -= dot_pos - 1 #减的1是为了上面减的1,有整数部分的和没有的不同
decimal_par = decimal_par[dot_pos:]
base = int_par[1:] + decimal_par
while len(base) < 52: #一共52位尾数位补齐
base += str(0)
exp_par = exp_bin(exp,bit_cnt=11)
ans = str(sign) + exp_par + base
return ans[:64]
二进制转float
#二进制部分指数数值计算
def bin_exp(num_str,bit_cnt=8):
ans = 0
pivot = 127 if bit_cnt == 8 else 1023
for i in range(bit_cnt):
ans <<= 1
ans |= int(num_str[i]) #从低位开始取
return ans - pivot #阶数小于127则为纯小数,此处返回和127的差值
#二进制部分整数数值计算
def bin_int(num_str):
num_str = '1' + num_str #把尾数的前导1加上
ans = 0
for i in range(len(num_str)):
ans <<= 1
ans |= int(num_str[i])
return ans
#二进制部分小数数值计算
def bin_decimal(num_str):
ans = 0
for i in range(len(num_str)):
ans = (ans + 2**(-(i+1))) if num_str[i]=='1' else ans
return ans
def bin_float32(num_str):
sign = 1
if num_str[0] == '1':
sign = -1
exp = bin_exp(num_str[1:9])
int_par = 0
if exp < 0: #纯小数的情况
decimal_par = bin_decimal('0'*(abs(exp)-1)+'1'+num_str[9:])
else:
int_par = bin_int(num_str[9:9+exp])
decimal_par = bin_decimal(num_str[9+exp:])
ans = sign * (int_par+decimal_par)
return ans
def bin_float64(num_str):
sign = 1
if num_str[0] == '1':
sign = -1
exp = bin_exp(num_str[1:12],bit_cnt=11)
int_par = 0
if exp < 0: #纯小数的情况
decimal_par = bin_decimal('0'*(abs(exp)-1)+'1'+num_str[12:])
else:
int_par = bin_int(num_str[12:12+exp])
decimal_par = bin_decimal(num_str[12+exp:])
ans = sign * (int_par+decimal_par)
return ans
float尾数位修改
def modify_float(num,pos_seq,replace_seq,type=32): #pos_seq为修改位置(位置从尾数位最低位开始计算,0-x),replace_seq为具体修改的值
if len(pos_seq) != len(replace_seq):
print("修改序列位置和长度不一致")
return None
num_bin = float64_bin(num) if type == 64 else float32_bin(num)
list_bin = list(num_bin)
idx = 0
border = 51 if type == 64 else 22
for i in pos_seq:
if i > border:
print("超过尾数修改范围")
return None
list_bin[type-1-i] = str(replace_seq[idx])
idx += 1
num_bin = "".join(list_bin)
return bin_float64(num_bin) if type == 64 else bin_float32(num_bin)
字符和二进制的互转
#计算单个char(8位字符在数字和二进制之间的转换)
def str_bits(str):
ret = bin(ord(str))[2:]
while len(ret) != 8:
ret = '0' + ret
return list(ret)
def bits_str(bits):
ret = 0
tmp = "".join(bits)
for i in range(len(tmp)):
ret <<= 1
ret |= int(tmp[i])
return chr(ret)