-
符号(sign/s), 阶码(exponent/exp),尾数(significant/frac)
- float: s 1位, exp 8位, frac 23位 --------------------4字节
- double: s 1位, exp 11位, frac 52位-----------------8字节
-
小数转二进制方法:
乘二取整法:将小数部分乘以二, 然后取整数部分, 剩下的小数部分继续乘以二,知道小数部分为零为止。 -
尾数:尾数是作为无符号整数存储的(没有必要用有符号数)
-
余码/移码系统:
单精度使用余127码,双精度使用余1023码。127/1023为偏移量,即指数=阶码-偏移量。 -
被编码的值的情况:
-
规格化的值:
exp的位不全为0且不全为1,此时阶码字段被解释为以偏置 (biased)形式表示的有符号整数。此时指数 E = e − B i a s E = e-Bias E=e−Bias ;
因此与补码的范围不同,移码系统表示的指数范围为-126~+127 (float)。小数字段frac被解释为小数值f(0<=f&&f<1) , 尾数定义
为 M = 1 + f M=1+f M=1+f 。这种方式也别叫做隐含的以1开头的表示 。(因为整数位永远是1,所以就不显示的表示这个1了,类似科学表示法) -
非规格化的值:
exp的位全为0, E = 1 − B i a s E=1-Bias E=1−Bias , M = f M=f M=f (此处使用1-Bias而不是-Bias看似不合理,但这种方式却提供了一种从非格式化数转化为格式化的平滑过渡 )。非规格化数有两个用途,一是为浮点数提供了一种表示零的方法(由于规格化的值中隐式存在一个整数位1)。因此,在exp和frac全为零时,根据符号位不同出现了值+0.0和-0.0,且IEEE规定二者在某些方面是不同的某些方面是相同的(经过测试vs认为二者相同,python和Java似乎认为二者不同,具体估计取决于语言或者编译器实现)。二是非规格化数可以表示那些非常接近于零的数,它们提供了一种属性叫做逐渐溢出 ,其中可能的数值分布均匀的接近0.0 。 -
无穷大(特殊值):
exp的位全为1时, frac全为0时,此时的值表示无穷大。根据符号位不同分别表示正负无穷,无穷用来表示运算溢出时的结果。
-
NaN(特殊值):
exp的位全为1时,frac不为0,即为NaN(Not a Number)。一般计算结果不为实数或无穷时返回此指(比如sqrt(-1))。在某些应用中也用来表示未初始化的数据。
-
-
上溢和下溢
假设阶码为四位,则在发生上溢时,阶码为1111,表示为无穷大,发生下溢时,阶码为0000,由于阶码不能变得更小,只能尾数右移一位,即损失原本尾数最末位的位,以保证损失最小的精度(虽然依然可以表示,但在逐渐损失精度,因此float的取值范围为-2128-2^128^但精度只有67位,double的取值范围为-21024 ~ 21024 精度为15~16位)。当一个很小的数除以一个非常大的值的时候,会导致结果尾数全部为0 。 -
范围与精度
float的指数范围为-127~128,double的范围为-1023~1024,负指数决定了绝对值最小的非零数(零一之间),正指数决定了绝对值最大的数,也决定了浮点数的范围,float的范围有-2128~-2128,double的取值范围为-21024 ~ 21024 。 -
对于浮点数存储方式的问题解答:
-
非规格化数到规格化数的平滑过渡 是怎么回事?
假设浮点数为8位,1位表示符号,4位表示位阶,3位表示尾数。
根据上面的方式:
此时0 0000 000为+0,0 0000 001为最小非规格化数,0 0000 111为最大非规格化数,0 0001 000为最小规格化数, 0 1110 111为最大规格化数,0 1111 000为正无穷。
在最小规格化数中 阶码为0001,指数为-6(2-6=1/64),尾数为000,所以f=0,M=1+f=1。最小规格化数=M*1/64=1/64=8/512。
最大非规格化数中 阶码为0000,指数为1-Bias=-6(1/64),尾数为111,所以M=f=2-1+2-2+2-3 =7/8。即最大非规格化数=M*1/64 =7/512 。可见最大的非规格化数只比最小的规格化数小1/512,且越接近+0非规格化数越密集,即可以用非规格化数表达一些非常接近于0的数且非规格化数到规格化数有一个平滑过渡。 -
为什么使用余码系统来存储位阶而不是补码系统?
主要原因是对于浮点数的计算和比较大小的时候总会先比较指数的大小,在计算时要通过改变尾数(移动小数点)使阶码一致(对阶)。在使用补码的时候,要先转化为原码再进行比较,而由于移码全部都是正数可以直接进行比较(可以用非常简单的电路实现)。其次就是这样表示数据的话,其二进制序列完全是按升序排列的。
-
-
浮点数运算
(插一个题外话,补码运算)
加法直接用补码相加,发生上溢是舍弃溢出的位(左移)
减法依然补码相加,结果符号取较大绝对值整数的符号实数的加法和减法运算是在先将小数点对齐后以符号加绝对值格式存储的两整数的加法和减法运算。过程大体分为五步
-
去规格化
相当于在在规格化的数尾数部分包含隐藏的1且增加指数,此时尾部看作一个整数。
-
求阶差
查看两个指数是否相等,求阶差
-
对阶
增加比较小的指数,尾数右移
-
尾数相加
如果发生上溢,右移尾数(右规 )
-
结果规格化
为规格化的数隐藏整数部分的1
-
推荐看一下深入理解计算机系统