python-接近完美的单精度浮点数转换代码
浮点数存储
⼗进制浮点数转换为⼆进制浮点数:整数部分重复相除,⼩数部分重复相乘
整数部分重复相除:除基取余,直到商为0,余数反转
⼩数部分重复相乘:乘基取整,直到⼩数为0或者达到指定精度位,整数顺序排列
0.5
过程1:转换乘对应的⼆进制⼩数 0.1
过程2:转换成对应的指数形式 2**1 * 1.0
过程1分解,因为这⾥整数部分为0不⽤处理,相当于只需要了解怎么把⼗进制的.5变成⼆进制的.1,在⼈的思维中,这⾥的1就相当于2**-1,正好是0.5,但是这对计算机来说是没有意义的,计算机的运算器都是整数的运算,再观察,假设⽬标形态是x,0.5 * 2=1;x * 2=1,于是bin(0.1) is float(0.5),那么如何⽤0.5推导出0.1,* 2对⼆进制意味着是⽐特左移,⽽⼩数点左边,对于计算机来说,是不认识⼩数的,
于是只能当作整数处理,那么⼩数点左边这个整数就是5,5 * 2=10,即0.5 * 2=1,所以没假设的整数结果⼤于10后,就把这个⼗位拿掉存放起来,例如5 * 2⼀次就得到⼀个⼗位的1,拿掉1后就是0,获取⼩数结束:.1
那么为了知道规律,设定数值:bin(.11)即2**-1+2**-2即0.5+0.25即0.75
这⾥整数部分就是两位了,把这两个数当作整数就是75,那么要获取有效的1只能是百位:
75 * 2=150,拿掉百位的1,存储起来,待处理整数为50,50 * 2=100,拿掉百位的1,待处理数归零,取值结束,连续的获取了两个1,即bin(.11)
第⼀次拿掉的1,他表⽰的是0.5,第⼆次拿掉的1表⽰的是0.25,对应.11,第⼆次产⽣的1是放在第⼀次产⽣的1的后⾯。
假设我们不拿掉1,是否会有影响,150*2=300,个位、⼗位归零,运算结束,得到百位以上的数是3,3可以直接可以⽤⼆进制的数11表⽰,貌似也⾏。
⽅法1对应⽅法2的逻辑上的缺点:
1、貌似每次都要把超位的1都拿下来,这⼀步可以省去吗?
2、需要存储拿下来的1
优点:
1、超位后,拿掉⼀个位,之后就能少算⼀个位,于是每发⽣⼀次,之后运算压⼒都会减⼩,尤其是如果给⼀个⼩数点后很长数值的情况
2、接上,我们要每次都要推测超位的长度,因为我们规定了浮点数的数据存储长度就是那么多,存储长度盛满后,后⾯可能有的⼩数就要省略。⽽如果把位拿下来存在个东西⾥⾯,就只需要记录东西⾥⾯的长度。其实这⾥我很不确定,例如我⽤Python来表⽰,我会⽤到这个那个函数,但是我不知道机器中,是否有超位的部分的对应⼆进制的长度的运算⽅法。其实推测下来,可能的情况是待处理的数据其实是字符串,因为长度不定,计算机底层可能还⽆法存放那么长的数据,所以可能会需要⽤软件分割处理,所以不是单纯的数值,⽽数值只是计算的中间产物,⽽之后存放的⼆进制1,也是字符串,即:待处理字符串 == > 转换成运算器能处理的长度 == > 运算 == > 得到超位 == > 存放⾄表⽰⼆进制的字符串中。
上⾯提到的是⼩数部分如何转化成⼆进制⼩数部分,那么整数部分,其实就可以⽤⼗进制转⼆进制的⽅法直接转化成⼆进制整数部分。
但是当作⼀个模拟硬件⼯作的流程,整数的0~9以及个⼗百千⼜如何变成⼆进制保存和运算的呢。保存其实就是⼀串⼆进制的01的串⽽已,没有类型规定的话,就是RAW。
⼜要开始思考了,假设我们拿到⼀个功能,即⼆进制1000就直接对应8,再底层的功能我们不考虑。
那么64位的cpu,他⼀次运算的长度可以是1111…挺长的,那就短说,假设我们⽤的处理器是4004,⼀次运算长度是4bit,即1111,从左往右,1分别对应8、4、2、1,最⼤表⽰⽆符号⼗进制15,假设给出整数0~9的任意⼀个,例如8,他记住了bin(1000)是8,结果就直接出来了。例如7,他⾄少知道7⽐8⼩,⽐4⼤,所以7-4=3,同理3-2=1,于是0111,当然他也可能直接记住7是0111。那么给出16呢,超出15的界限,这才开始真正的思考⽽不是推测+思考。16是⼀个字符串,他符合整数的书写规则,⽽且我们也是要把他当作整数处理。底层库中并没有他的数据,但是运算器中有3/2=1…1;5/2=2…1;6/2=3;7/2=3…
1;9/2=4…1的数据,16就是⼀个⼗位的1和⼀个个位的6,16/2=(10+6)/2=5+3=8,⽽8正好是1000,⽽⼗进制的/2运算就是⼆进制的位移运算,所以16的⼆进制形态就是10000,那么17呢,17/2=(10+7)/2=8…1,余号前⾯意味着仍有10000,但余数意味着之前有个1,那么就是10000+1=10001。貌似有了苗头,只需要定义⼀个10/2=5。
那么⼀个更⼤点更复杂的数,例如bin(111111),int(0b111111): 63。求63在4004下转成⼆进制形态的
过程。
5/2=2…1 : 1 2/2=1…0 : 0 1/2=0…1 : 1 5:bin(101)
bin(1010):10 10/2=5…0 : 0 5 : 101 越开始的位,越是⼆进制的低位(右侧)
s=str(i%2)+s
i=i//2
>>>s '1010011000' ```缕⼀缕思路,只要整数/2,⽆论整除还是有余,得到的结果相对于⼆进制来说,都是上了⼀位。⽽余数就是当前位置⼆进制的单位。
⽆注释版:
import re
while1:
num =str(input("输⼊⼀个数,显⽰其浮点数在⼆进制中的存储,输⼊exit退出:"))
if num=="exit":
print("退出运算")
break
break
if num=="0":
print("00000000000000000000000000000000")
continue
if num=="nan":
print("01111111110000000000000000000000")
continue
if num=="inf":
print("01111111100000000000000000000000")
continue
if num=="-inf":
print("11111111100000000000000000000000")
continue
if((not repile("[^0-9.\-+]+").findall(num)) \
and repile("[0-9]+").findall(num) \
and((unt("-")==unt("+")==0) \
unt("+")==unt("-")==1and num[0]=="-") \
unt("-")==unt("+")==1and num[0]=="+")) \ unt(".")==unt(".")==1)):
if num[0]=="-":
sign="1"
num=num[1:]
elif num[0]=="+":
sign="0"
num = num[1:]
else:sign="0"
unt("."):
numi=num[0:num.find(".")]
numm=num[num.find(".")+1:]
else:
numi = num
numm ="0"
if numi=="0"and numm=="0":
print("00000000000000000000000000000000")
continue
numib=bin(int(numi if numi else"0"))[2:]
if numm!="0":
nummb=""
top=10**len(numm)
numm=int(numm)
if numib !="0":
lmb=(25-len(numib))
while len(nummb)<lmb:
numm=numm*2
if numm>top:
nummb+="1"
numm-=top
elif numm==top:
nummb +="1"
break
else:nummb +="0"
else:
for i in range(126):
numm = numm *2
if numm<top:nummb +="0"
elif numm>top:
nummb +="1"
numm -= top
for i in range(24):
numm = numm *2
numm = numm *2
if numm > top:
nummb +="1"
numm -= top
elif numm == top:
nummb +="1"
break
else:
nummb +="0"
break
elif numm==top:
nummb +="1"
break
if"1"not in nummb:
print("数值过⼩,赋值为0\n00000000000000000000000000000000")
continue
else:nummb="0"
numb=numib+"."+nummb
nume=numb.find(".")-1if numb.find("1")<numb.find(".")else-(numb.find("1")-1) print(numb)
if nume>127:
print("数值过⼤,超出范围")
continue
exponent=bin(nume+127)[2:].rjust(8,"0")
mantissa=numb[:numb.find(".")]+numb[numb.find(".")+1:]
mantissa=mantissa.lstrip("0")
print(bin(nume+127))
if sign=="0"and len(mantissa)==25and mantissa[24]=="1":
mantissa=bin(int(mantissa[:25],2)+1)[2:]
if len(mantissa)==26:
exponent=bin(nume+127+1)[2:].rjust(8,"0")
if len(mantissa)<25:print("该浮点数精确⽆舍⼊")
else:print("该浮点数不精确有舍⼊")
mantissa=mantissa[1:24].ljust(23,"0")
numf=sign+exponent+mantissa
print(numf)
else:
print("格式错误,⽆法转换为浮点数")
注释版:
import re
# ⾸先我们要知道在没有软硬件⽀持浮点数的那个时代,先贤们是怎么定义了单精度浮点数
# 并利⽤那时的条件运算出来。经过多次改良优化后,我攒出了以下代码
# ⾸先要了解单精度浮点数:32位的存储长度,其中第⼀位存储正负号:sign bit
# 接下来的⼋位存储指数:2**E,exponent,8位⼆进制范围是0~256,但因为之后
python代码转换# 定义基数为1.x的原因,所以E要适应有效数字在⼩数点前咋滴咋滴,⼩数点后咋滴咋滴
# 所以将01111111,即127作为基准位0。所以E的有效范围是-127~128,但⼜因为在浮点系统中# 定义了⼏个特殊的项,所以还是占⽤了⼏个E,⼤家可以⽤struct玩玩看
# 基数,1.x,在浮点数的⼆进制中,1会被隐去。.x的⼆进制占23位。python与IEEE754
# 在最后位除⾮被其舍去的下⼀位有分歧,python是0舍1⼊。IEEE754是直接截断。(可能)
# 所以我在代码中做了第25位的判断 /嘿嘿嘿⼜优化了运算过程,并给出数值是否被舍⼊
while1:
num =str(input("输⼊⼀个数,显⽰其浮点数在⼆进制中的存储,输⼊exit退出:"))
if num=="exit":#此处⼏个if是float定义的⼏个量
print("退出运算")
break
if num=="0":#此处⼏个if是float定义的⼏个量
if num=="0":#此处⼏个if是float定义的⼏个量
print("00000000000000000000000000000000")
continue
if num=="nan":#没有数
print("01111111110000000000000000000000")
continue
if num=="inf":#⽆穷⼤
print("01111111100000000000000000000000")
continue
if num=="-inf":#⽆穷⼩
print("11111111100000000000000000000000")
continue
#检测字符串是否符合浮点数规格
if((not repile("[^0-9.\-+]+").findall(num)) \
and repile("[0-9]+").findall(num) \
and((unt("-")==unt("+")==0) \
unt("+")==unt("-")==1and num[0]=="-") \
unt("-")==unt("+")==1and num[0]=="+")) \ unt(".")==unt(".")==1)):
#判断正负
if num[0]=="-":
sign="1"
num=num[1:]
elif num[0]=="+":
sign="0"
num = num[1:]
else:sign="0"
#分离整数部分和⼩数部分
unt("."):
numi=num[0:num.find(".")]
numm=num[num.find(".")+1:]
else:
numi = num
numm ="0"
if numi=="0"and numm=="0":
print("00000000000000000000000000000000")
continue
#整数部分的⼆进制
# 虽然这⾥我⽤了bin直接转换整数为⼆进制,但是实际上
# 那个年代使⽤的整数是多少位的,因为浮点数最⼤⽀持3.x * 10**38
# 要远⽐int⼤的多
numib=bin(int(numi if numi else"0"))[2:]
#⼩数部分的⼆进制
#如果numm不为0,进⾏运算,else,直接赋值nummb="0"
if numm!="0":
#存储⼆进制的字符串
nummb=""
#作为⽐较的基数,之后底数*2,⼆进制的意思就是向左位移1
# 等⼀等,那我岂不是,冷静下,不是这样的,因为这⾥要算出
# 对应的浮点数的⼩数点⼆进制部分,⽽此时根本不知道⼩数点
# ⼆进制部分如何表⽰,这⾥就是要运算出来,⽽不是单纯的
# 向左位移,⽽top这个就想到与⼆进制中的1的位置,⽽⼩数点
# 后的⼆进制则是⿊盒,现在就是要⽤*2,即⿊盒中的现在不知
# 但以后确实能存在的⼆进制浮点数给推出来
top=10**len(numm)
numm=int(numm)
#如果整数部分存在数值,先贤们⽤32位定义为单精度浮点数
# 经过指数运算后最终留给1.x的.x表⽰长度是23个⼆进制位
#为了节省运算效率,不做多余的⼀丁点的运算,所以这⾥分叉了
# 未优化前可是算152次的 127+25

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。