一、你需要知道什么
首先要解释这一点,必须先确保你看得懂二进制的数字代表多少。
举个例子:1001代表多少?
9?ok,如果你能回答上来,那咱可以继续聊下去,否则建议先去看看二进制的表示
二、咱先简单表示一下小数
我们知道,1001代表9是因为他是2^0+2^3,那么现在,我们在最右边的1前面加个小数点
现在数字就变成了100.1,那么这个代表什么?
前面的三位100,代表4(就是二进制的表示方法),后面的.1代表2^-1(很明显,.1是2^-1,那么.01就是2^-2,.001就是2^-3,以此类推),即0.5,所以总共这个数就是4.5
4.5和9的关系正好就是二分之一的关系(也不是正好,右移了一位嘛毕竟),所以9就可以写成4.5*2=100.1*2(为了方便理解,前面是二进制,后面是十进制)
同样的,9=10.01*2^2=1.001*2^3
三、浮点数咋表示呢
那么,是不是所有的数字都可以表示成这种M*2^E的形式?
当然不是,咱毕竟还有负数,所以加个符号位:(-1)^S*M*2^E
完美!!!!!
诶,IEEE那群人也是这样想的,于是现在浮点数的标准就出来了
这张图是大家都看过的(当然没看过也没关系),但是估计很多人看网上千篇一律的解释的时候都是一脸懵逼(不然也不会点进我这篇博文)
我们现在知道,浮点数的表示形式就是(-1)^S*M*2^E,那么我跟大家说一下这三个段和这个式子的关系
S:s代表符号位,什么精度的都是只有一位,1位负,0位正,他和式子中的s是等价的
EXP:指数位,他编码了E,但是不是完全相等(但是现在你可以认为指数位就是等于E,接下来我会以指数位=E举例,并且告诉你为什么是错的)
FRAC:尾数位:他编码了M,但是不完全相等(同样现在你可以认为相等,接下来我同样会举例)
四、为什么M不能直接等于FRAC,E不能直接等于EXP
ok,浮点数有单精度和双精度,但那些位数太大了,并不好举例,所以我临时创一个短精度浮点数,它的S有1bit,EXP4bit,FRAC3bit,总共八个字节。
还是比如9,他等于1.001*2^3,那么如果EXP=E,FRAC=M,这个数字用咱们的短精度浮点数就可以表示为:0 0011 100(1),第一位是符号位,0为正,然后四位是EXP=3,后面1001代表M,因为咱这边的FRAC只有3位,很不幸,最后一位1会被舍去。
所以,如果按照上述来,咱最后的短精度数字表示为0 0011 100,按照(-1)^S*M*2^E来算(M=100=1.00=1,E=0011=3),最终等于8,很尴尬,变成咱的短精度浮点数之后连9这么小的数字都变得不精确了。
那么怎么办呢?我们知道,浮点数是按照(-1)^S*M*2^E来算的,而M总是等于1.xxxxx,那么干脆这样,咱不表示M最前面的那个1了,咱直接默认有个1,对于9来说,他等于1.001*2^3,那么就可以表示为:0 0011 001,咱表示出来9了,很精确!!!!!!!
ok,IEEE那群人同样是这样想的,所以他们也这样干了,所以M和FRAC的关系就是:FRAC代表了M的小数点后的数字,不包括小数点前的那个1。
那么接下来,对于咱的短精度数:0 1111 100代表什么呢?
第一位0,所以是正数
然后四位1111,为-1,所以E=-1
然后三位100,为小数点后的,所以是2^-1=0.5,所以M=1+0.5=1.5
所以这个数字就是(-1)^0*1.5*2^-1=0.75
OK,我们看看9和0.75,你可以很容易看出这样表示有什么不好
9 ----------> 0 0011 001
0.75-------->0 1111 100
9明明是比0.75大的,但是看起来却像是比0.75小一样,并且,如果交给计算机去处理,计算机先看一下符号位,再看指数位,把他转化成补码,再比较,计算机表示很累
那么,可不可以在指数位时:1xxx代表2的正次方,0xxx代表2的负次方
现在咱们有两种方案:
一:把指数位看成无符号数,1000代表0次方
二:把指数位看成无符号数,0111代表0次方
IEEE那群人选择了第二种,所以E=EXP-(2^(k-1)-1),而k就是EXP的位数,在咱的短精度浮点数中,k=4,2^(k-1)-1就被称为bias(偏置数)
ok,到了现在,对于浮点数咱已经了解80%了,现在请仔细回想一下你了解的浮点数。
五、特殊情况
到现在为止,浮点数能表示0吗?
对于最小的正数0 0000 000,通过刚刚的规则来看是不是应该是(-1)^0*1^2(-7)=0.008左右,到不了0,很尴尬。
IEEE想了个骚办法,当exp全部为0时,咱用不同的规则
这种骚办法一般人想不出来,我就直接说了:
exp等于0时
M=FRAC,没有那个默认的1
E=1-bias,对于咱的短精度来说,EXP=0时,E一直为-6
那么我们看看现在的短精度数字是咋样的
0 0000 000 ---------->0
0 0000 001 ---------->2^(-6)*2^(-3)=1/512
0 0000 010 ---------->2^(-6)*2^(-2)=2/512
0 0000 011 ---------->2^(-6)*(2^(-2)+2^(-3))=3/512
.............
0 0000 111 ---------->2^(-6)*(2^(-1)+2^(-2)+2^(-3))=7/512
0 0001 000---------->2^(-6)*1=8/512(注意这里exp不是全0所以规则变了)
0 0001 001---------->2^(-6)*(1+2^(-3))=9/512
我擦,明明是不同的规则,但是数据的过渡却异常平滑
那么对于exp全为1的情况,有没有什么特殊呢?
如果我们想要表示无穷大,exp设为全1,frac设为全0就代表无穷大
如果我们要表示非数字,exp设为全1,frac设为非全0就代表非数字
六、规则总结
ok,现在我们已经知道了浮点数的规则,回顾一下:
1、浮点数的表示形式是:(-1)^S*M*2^E
2、浮点数在位中的表示形式是S+EXP+FRAC
3、对于EXP非全0或全1:S=S, E=EXP-(2^(k-1)-1), FRAC=M小数点后的数字
4、对于EXP全0:S=S, E=1-bias, FRAC=M
5、对于EXP全1:FRAC全0=无穷大, FRAC非全0=非数字
七、浮点数运算
1、乘法:
用我们能理解的思维来看:a=1.5*2^2 b=1.25*2^3
那么a*b=1.5*1.25*2^(2+3)
所以对于乘法,则是指数相加,尾数相乘
尾数乘了之后如果大于2,则指数加一位,尾数右移一位
尾数乘了之后如果位数过多则以四舍六入五成双的原则舍入
指数相加之和如果溢出则变为无穷大
2、加法:
同样的:a=1.5*2^2 b=1.25*2^3
那么对于a+b,咱得先把指数弄相同,则可以把1.5>>1,2^2变成2^3
但是对于浮点数的形式来说,很重要的一点就是M是有一个隐藏的1,右移的时候得把那个1带上
指数相同之后,尾数相加就行了
尾数加了之后如果位数过多则以四舍六入五成双的原则舍入,这也是为什么大的浮点数加小的浮点数加了之后跟没加一样,因为小的那个M右移的过多,直接移没了
————————————————
版权声明:本文为CSDN博主「努力学习小十二」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Mrlie/article/details/123104570