python - 接近完美的单精度浮点数转换代码

浮点数存储

十进制浮点数转换为二进制浮点数:整数部分重复相除,小数部分重复相乘
整数部分重复相除:除基取余,直到商为0,余数反转
小数部分重复相乘:乘基取整,直到小数为0或者达到指定精度位,整数顺序排列
匠心之作java基础强化之强转溢出&浮点数运算精讲

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,也是字符串,即:待处理字符串 == > 转换成运算器能处理的长度 == > 运算 == > 得到超位 == > 存放至表示二进制的字符串中。

上面提到的是小数部分如何转化成二进制小数部分,那么整数部分,其实就可以用十进制转二进制的方法直接转化成二进制整数部分。

Python 十进制转二进制

但是当作一个模拟硬件工作的流程,整数的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,无论整除还是有余,得到的结果相对于二进制来说,都是上了一位。而余数就是当前位置二进制的单位。

python - 接近完美的单精度浮点数转换代码_第1张图片

无注释版:

import re

while 1:
    num = str(input("输入一个数,显示其浮点数在二进制中的存储,输入exit退出:"))
    if num=="exit":
        print("退出运算")
        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 re.compile("[^0-9.\-+]+").findall(num)) \
            and re.compile("[0-9]+").findall(num) \
            and ((num.count("-") == 0 and num.count("+") == 0) \
                 or (num.count("+") == 0 and num.count("-") == 1 and num[0] == "-") \
                 or (num.count("-") == 0 and num.count("+") == 1 and num[0] == "+")) \
            and (num.count(".") == 0 or num.count(".") == 1)):

        if num[0]=="-":
            sign="1"
            num=num[1:]
        elif num[0]=="+":
            sign="0"
            num = num[1:]
        else:sign="0"

        if num.count("."):
            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
                            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(".")-1 if 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)==25 and 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,但因为之后
# 定义基数为1.x的原因,所以E要适应有效数字在小数点前咋滴咋滴,小数点后咋滴咋滴
# 所以将01111111,即127作为基准位0。所以E的有效范围是-127~128,但又因为在浮点系统中
# 定义了几个特殊的项,所以还是占用了几个E,大家可以用struct玩玩看
# 基数,1.x,在浮点数的二进制中,1会被隐去。.x的二进制占23位。python与IEEE754
# 在最后位除非被其舍去的下一位有分歧,python是0舍1入。IEEE754是直接截断。(可能)
# 所以我在代码中做了第25位的判断 /嘿嘿嘿 又优化了运算过程,并给出数值是否被舍入
while 1:
    num = str(input("输入一个数,显示其浮点数在二进制中的存储,输入exit退出:"))
    if num=="exit":#此处几个if是float定义的几个量
        print("退出运算")
        break
    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 re.compile("[^0-9.\-+]+").findall(num)) \
            and re.compile("[0-9]+").findall(num) \
            and ((num.count("-") == 0 and num.count("+") == 0) \
                 or (num.count("+") == 0 and num.count("-") == 1 and num[0] == "-") \
                 or (num.count("-") == 0 and num.count("+") == 1 and num[0] == "+")) \
            and (num.count(".") == 0 or num.count(".") == 1)):

        #判断正负
        if num[0]=="-":
            sign="1"
            num=num[1:]
        elif num[0]=="+":
            sign="0"
            num = num[1:]
        else:sign="0"

        #分离整数部分和小数部分
        if num.count("."):
            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
            if numib != "0":
                lmb=(25-len(numib))
                while len(nummb)<lmb:
                    # *2相当于<<1
                    # 这里就是要把小数点后的二进制排列给挤出来
                    numm=numm*2
                    if numm>top:
                        nummb+="1"
                        numm-=top

                    #之前写过一个代码,有类似的过程,因为预先知道
                    # 之后不会有东西了,锁了舍去了num-的过程
                    # 直接跳出,但之后有用到num==0的判断,所以
                    # 这里激灵了一下,大概之后用不到numm了吧!?
                    elif numm==top:
                        nummb += "1"
                        break
                    else:nummb += "0"
            else:
                # 这个岔路,是整数部分为0的情况,所以1.x的位置很不确定
                # 所以就开始算,直到第一个有效数字出现,然后再算24个数字
                # 之前说过无脑152,但是这里简化以下,如果在e的最大值126下
                # 仍然无法得到有效数值,就直接赋值为0
                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
                            if numm > top:
                                nummb += "1"
                                numm -= top
                            elif numm == top:
                                nummb += "1"
                                break
                            else:
                                nummb += "0"
                        break
                    elif numm==top:
                        nummb += "1"
                        break
            # if nummb.find("1") == -1:
            # 文档说了,判断有没有用in,不用find
            if "1" not in nummb:
                print("数值过小,赋值为0\n00000000000000000000000000000000")
                continue
        else:nummb="0"

        #原始过程中的浮点数二进制不带正负号
        numb=numib+"."+nummb

        #原始二进制浮点转换成 1.x*(2**E) 计算2**E,指数
        nume=numb.find(".")-1 if 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")

        #规整1.x
        mantissa=numb[:numb.find(".")]+numb[numb.find(".")+1:]
        mantissa=mantissa.lstrip("0")
        print(bin(nume+127))
        #判断是否需要入尾位,这个是python的特殊定义,IEEE 754 单精度浮点数转换并无舍入

        if sign=="0" and len(mantissa)==25 and 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("格式错误,无法转换为浮点数")

以上是第三,不,第四天的码了,准确的说是从想写一个码开始,第五天了。这几天没什么学习进度,心里挺焦急的!

而实际上python默认并不会用到单精度浮点数,所以struct中的末位0舍1入到底是怎样,不的而知。
看看python实际上用的双精度浮点数吧!

In [87]: struct.unpack("!d",b'\x3f\xff\xff\xff\xff\xff\xff\xff')
Out[87]: (1.9999999999999998,)

In [90]: struct.pack("!d",1.9999999999999998)
Out[90]: b'?\xff\xff\xff\xff\xff\xff\xff'

In [91]: 2**-53
Out[91]: 1.1102230246251565e-16

In [92]: struct.pack("!d",1.99999999999999986)
Out[92]: b'?\xff\xff\xff\xff\xff\xff\xff'

In [93]: struct.pack("!d",1.99999999999999987)
Out[93]: b'?\xff\xff\xff\xff\xff\xff\xff'

In [94]: struct.pack("!d",1.99999999999999988)
Out[94]: b'?\xff\xff\xff\xff\xff\xff\xff'

In [95]: struct.pack("!d",1.99999999999999989)
Out[95]: b'@\x00\x00\x00\x00\x00\x00\x00'

In [96]: struct.unpack("!d",b'@\x00\x00\x00\x00\x00\x00\x00')
Out[96]: (2.0,)

In [97]: a=1.99999999999999989

In [98]: a
Out[98]: 2.0

In [99]: a=1.99999999999999988

In [100]: a
Out[100]: 1.9999999999999998

我要放弃思考

=============================================================================

两天,没白费,期间搞出好多问题,现在接近于当初还没有浮点软硬件支持时,前辈大佬们的想法了吧!

第二版,参照了前辈的代码思路 \心痛.png

import re

while 1:
    num = str(input("输入一个数,显示其浮点数在二进制中的存储,输入exit退出:"))
    if num=="exit":#此处几个if是float定义的几个量
        print("退出运算")
        break
    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 re.compile("[^0-9.\-+]+").findall(num)) \
            and re.compile("[0-9]+").findall(num) \
            and ((num.count("-") == 0 and num.count("+") == 0) \
                 or (num.count("+") == 0 and num.count("-") == 1 and num[0] == "-") \
                 or (num.count("-") == 0 and num.count("+") == 1 and num[0] == "+")) \
            and (num.count(".") == 0 or num.count(".") == 1)):

        #判断正负
        if num[0]=="-":
            sign="1"
            num=num[1:]
        else:sign="0"

        #分离整数部分和小数部分
        if num.count("."):
            numi=num[0:num.find(".")]
            numm=num[num.find(".")+1:]
        else:
            numi = num
            numm = "0"

        #整数部分的二进制
        numib=bin(int(numi if numi else "0"))[2:]

        #小数部分的二进制
        if numm:
            nummb=""
            top=10**len(numm)
            numm=int(numm)
            print(numm)
            while len(nummb)<152:
                numm=numm*2
                if numm>=top:
                    nummb+="1"
                    numm-=top
                else:nummb+="0"
        else:nummb="0"

        #原始过程中的浮点数二进制不带正负号
        numb=numib+"."+nummb

        #原始二进制浮点转换成 1.x*(2**E) 计算2**E,指数
        nume=numb.find(".")-1 if numb.find("1")<numb.find(".") else -(numb.find("1")-1)
        exponent=bin(nume+127)[2:].rjust(8,"0")

        #规整1.x
        mantissa=numb[:numb.find(".")]+numb[numb.find(".")+1:]
        mantissa=mantissa.lstrip("0")

        #判断是否需要入尾位,这个是python的特殊定义,IEEE 754 单精度浮点数转换并无舍入
        if sign=="0" and mantissa[25]=="1":
            mantissa=bin(int(mantissa[:25],2)+1)[2:]
            if len(mantissa)==26:
                exponent=bin(nume+127+1)[2:].rjust(8,"0")

        #拼接浮点二进制
        mantissa=mantissa[1:24].ljust(23,"0")
        numf=sign+exponent+mantissa
        print(numf)

    else:
        print("格式错误,无法转换为浮点数")

参考:Python实现十进制小数转IEEE754单精度浮点数转换
参考中的代码有一次bug,是因为引入了浮点运算,浮点运算的舍入和内部显示导致结果会出现偏差甚至错误。
我改进了下,以至于以上代码是纯整数运算,并添加了python的舍入机制。

之前搞的错误思路的代码,贴在下边,删除以前的错误文章!

python - 浮点数的存储结构 一笔笔教你怎么算

我犯了个错误,本想用一段代码表示浮点的转换存储,但是里面却不断的使用着与浮点相关的运算,如果这几一个实用的东西的话,她就是个死循环。
1、一开始赋值就转换成float,这导致之后接受的都是转换后的数据,大几率的错误性
例如,了解浮点存储的,再去想最大浮点值
0 11111110 11111111111111111111111
+ 2**127 *1.99999999…=3.402823669209385e+38
我就想到0.9999999999999…这个很边缘的值,他在浮点M值以外的位舍入后,就是1.0了,而float就是这样干的
在此之前我就针对进位做了个运算了,但用0.9999999999999…验证时,才注意到了最初我就犯了错误。
本想着再模拟486以前的没有浮点机制的时候去写个。思路很难,即便完成了指数的取值,小数部分的取值又要涉及到浮点运算。
而且浮点之所以这么存储,大概也是为了做浮点间的运算的方便,之后就是一个个很深的水了,于是虽然不想放弃的我,放弃这个问题,赶紧学下去才是关键吧!至于那个往上的在线运算器,会不会就是利用struct写的,毕竟就是一句话的事!即便也是用输入是字符串,解析成浮点存储结构,也不难,但如果真的没有利用一点浮点运算,大家能写出来吗?

IEEE 754 单精度浮点数转换
我嗅探了下网络,这个运算是联网的,网址所在地:美国俄勒冈波特兰 亚马逊云

不过我还是想尝试下至少一开始是字符输入接收为字符串的方法

=======================================================
这段代码并不完善,但大家可以先看看,完善的代码在后面。

第一版:用的是算数的思路,自己啃书,磕出来的代码,在纸上算的话,可以说是完美,但是在电脑上算,涉及到了好多那个时代不该出现的浮点运算,甚至最开始输入的字符串转化时,就是转化成了浮点数,最关键的是他可能会发生舍入导致结果不是我们输入的那个结果,所以虽然是一个纸上的完美思路。但是实际仅有教学价值了吧!

while 1:
    try:#如果输入转化失败,激发之后的except:break,结束程序
        num=float(input("请输入一个浮点数,非数结束:"))
    except:break
    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

    # 判断符号位 S:sign bit
    sign= "0" if num>0 else "1" #简化后的代码
    # if num>0:sign="0"
    # else:sign="1"

    # 推算指数 E:exponent 指数
    # 将数累计计算直到1.x的格式,一切都是二进制运算
    e=0
    if num>=2:
        while num>=2:
            num/=2
            e+=1
    elif num<1:
        while num<1:
            num*=2
            e-=1
    #以上累计的e
    exponent=bin(e+127).replace("0b","").rjust(8,"0")

    # 推算尾数 M:mantissa 尾数、小数部分
    num-=1
    if num==0:
        print(sign+exponent+"00000000000000000000000")
        continue
    mantissalist=[]
    #这里我一开始是使用字符串的,但是最后一位判断的原因,
    # 字符串无法修改,所以做成了列表
    for i in range(1,24):
        b=2**-i
        if num>b:
            num-=b
            mantissalist.append("1")
        elif num==b:
            num -= b
            mantissalist.append("1")
            break
        elif num<b:
            mantissalist.append("0")
    # print(i,num==0) #debug时增加的输出

    # 判断是否计算到最后位还有余数,余数是否大于等于无法显示的那位
    # 如果是,舍入结果是可显示的最后一位是1,这里我无法断定如果等于
    # 的话会怎样因为根本无法把正好等于的那个数打进去,但八成就是这样
    if i==23 and mantissalist[22]=="0" and num>=2**-24:
        mantissalist[22]="1"
    mantissa=''.join(mantissalist).ljust(23,"0")
    print(sign+exponent+mantissa)

以上是用python模拟的float存储方式,大家可以对应系统自带的一个库算出的结果对照,但是那个库貌似也不是真实存储状态,反正差不多!
这个是调用struct模块,返回各种效果,数据准确,大概。就是这里,给出的结果是0舍1入,至于python实际,要不咱算算?

import struct
# def binary(num):
#     return ''.join(bin(ord(c)).replace('0b', '').rjust(8, '0') for c in struct.pack('!f', num))
# 上面注释掉的是源代码,总是报错
while 1:
    try:a=float(input("输入一个数,他会输出对应的浮点数结构,输入非数类退出:"))
    except:break
    else:
        print(''.join(bin(h).replace('0b','').rjust(8,'0') for h in struct.pack('!f',a)))

# 这里是我在写模拟过程时,用的0.0456与最后一位何时0何时1调用的几个参数
# print(struct.pack('!f',0.04559999704360962))
# print(struct.unpack('!f',b'=\xcc\xcc\xcd'))
# print(struct.unpack('!f',b'=:\xc7\x11'))
# print(struct.unpack('!f',b'=:\xc7\x10'))

使用unpack得到:
01110101100011100010001 0.04560000076889992
01110101100011100010000 0.04559999704360962
最后一位1,0.00000000372529030
0.04560000263154507

In [21]: struct.pack("!f",0.0455999979749322)
Out[21]: b'=:\xc7\x10'

In [22]: struct.pack("!f",0.04560000263154507)
Out[22]: b'=:\xc7\x12'

In [23]: struct.pack("!f",0.04560000263154506)
Out[23]: b'=:\xc7\x11'

额,不行,这个舍入无视末位0还是1,只要进位,可能会一串上去
还需要改

==========================================
额,暂时算法上搞定了,但是突然觉得这里从字符串该过来的列表又没必要了,所以再简化成字符串吧!

while 1:
    try:#如果输入转化失败,激发之后的except:break,结束程序
        num=float(input("请输入一个浮点数,非数结束:"))
    except:break
    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

    # 判断符号位 S:sign bit
    sign= "0" if num>0 else "1" #简化后的代码
    # if num>0:sign="0"
    # else:sign="1"

    # 推算指数 E:exponent 指数
    # 将数累计计算直到1.x的格式,一切都是二进制运算
    e=0
    if num>=2:
        while num>=2:
            num/=2
            e+=1
    elif num<1:
        while num<1:
            num*=2
            e-=1
    #以上累计的e
    exponent=bin(e+127).replace("0b","").rjust(8,"0")

    # 推算尾数 M:mantissa 尾数、小数部分
    num-=1
    if num==0:
        print(sign+exponent+"00000000000000000000000")
        continue
    mantissalist=[]
    #这里我一开始是使用字符串的,但是最后一位判断的原因,
    # 字符串无法修改,所以做成了列表
    for i in range(1,24):
        b=2**-i
        if num>b:
            num-=b
            mantissalist.append("1")
        elif num==b:
            num -= b
            mantissalist.append("1")
            break
        elif num<b:
            mantissalist.append("0")
    # print(i,num==0) #debug时增加的输出

    # 判断是否计算到最后位还有余数,余数是否大于等于无法显示的那位
    # 如果是,舍入结果是可显示的最后一位是1,这里我无法断定如果等于
    # 的话会怎样因为根本无法把正好等于的那个数打进去,但八成就是这样
    if i==23 and num>=2**-24:
        # exec("mantissa=(bin(int(%s)+1).replace('0b','').rjust(23,'0')[-1:-24:-1][::-1])"%('0b'+''.join(mantissalist)))
        mantissa=(bin(int('0b'+''.join(mantissalist),2)+1).replace('0b','').rjust(23,'0')[-1:-24:-1][::-1])
    else:mantissa=''.join(mantissalist).ljust(23,"0")
    print(sign+exponent+mantissa)

还是有毛病,致命的大毛病,我获取的num本身其实就是个float,所以我不能使用a=float(input())。
而是要用a=str(),然后判断他是否符合录入对像的规则。

因为我录入0.9999999999999999999999,模拟她肯定接近于1,所以她的存储和1是一样的,于是struct是的,但是我的也是的,但我的不该是呀!所以错了!

请输入一个浮点数,非数结束:0.0456
0.0456
 01111010
00111101001110101100011100010001
请输入一个浮点数,非数结束:0.99999999999999999999999999999999
1.0
 01111111
00111111100000000000000000000000

于是我又加了个print,果然如此,所以继续改!亏的看了,不然真就错了!看来我注定不是一个码农,而是一个自由者!

你可能感兴趣的:(python)