类似十进制,二进制的小数点移动同样是乘以基数2的N次方,正的N次方数代表右移小数点,负的N次方代表左移小数点
而在十进制中,有我们熟悉的科学计数法来简便大数的表达,同样二进制也有浮点数表示法来表示简便大数的表示
让同样N位二进制的数能比原码表示更大范围的数
浮点数的基本构成:
同样还是参照十进制的科学计数法
因为对于十进制的10的N次幂写法有多种多样,除了要省去多余的0以外,还要保证小数部分都在开区间(-10,0)U(0,10)内,以此来统一科学计数法的表达方式
而二进制也有同十进制科学计数法类似的表达方式,即规格化浮点数,其中包括两种操作
- 左归:尾数算术左移一位,阶码减一,左归可能需要多次
- 右归:当浮点数运算的结果尾数发生溢出(双符号位为01或10),则尾数算术右移一位,阶码加一,只需要进行一次
规格化的尾数形式:
- 原码正数规格化后为【0.1xxx x】的形式
- 原码负数规格化后位【1.1xxx x】的形式
- 补码正数规格化后为【0.1xxx x】的形式(正数补码不变,所以和正数原码一样)
- 补码负数规格化后为【1.0xxx x】的形式
由于浮点数中阶码和尾数的位数没有一个明确的要求,则在使用的过程难免会有不统一的情况,于是就有了IEEE 754标准
按照IEEE 754的标准,常用浮点数的格式如下:
其中在IEEE 754标准中,对于阶码和尾数的位数有如下标准(短浮点数和长浮点数分别对应C语言的float和double类型)
(1)关于阶码的移码表示:
从IEEE 754标准的浮点数格式中我们发现,只有一个数符来代表尾数的正负,那么阶码的正负如何计算呢?
例如在短浮点数中,阶码的位数是8bit
- 视为有符号数来表示范围为 [ -127,+127 ]
- 视为无符号数来表示范围为 [ 0,+255 ]
其中0(全0)代表该数为非规格化数,255(全1)表示无穷大,即阶码超出了浮点数可表示的范围
于是我们可以用无符号数的范围去表示有符号位的范围,正好对应着移码的表示方式,通过偏置值来将转换数值
例如阶码的移码表示值为96,通过偏置值减去127得到实际阶码的值为【-31】
(2)关于尾数的原码表示:
在浮点数规格化操作中我们可以知道,原码尾数的正数和负数规格化后小数点后第一位必然为1
所以在IEEE 754标准中,小数点后的1不必存储下来,使得尾数能多表示一位,在读取浮点数的时候默认小数点后有一位1
例如:【+1100】规格化后为【0.11 × 24】,其中阶码部分为【4 + 127 = 131】
浮点数的加减法包括五步:
- 对阶:小阶向大阶靠齐,使两个浮点数的阶数相同,该过程可能会发生位数低位丢失导致精度丢失
- 尾数加减:原码加减法
- 规格化:根据尾数的形式进行规格化
- 舍入:假设尾数只有8位,则在上述对阶和右规的过程中都发生了低位丢失
(1)“0”舍“1”入:若丢弃位为0,则直接舍去,若丢弃位为1,则尾数末位进1(可能会再次溢出)
(2)恒置“1”法:丢弃位丢弃后,尾数末尾始终置为1,可能会使尾数增大(正数)和变小(负数)
- 溢出判断:
(1)由于尾数溢出时会通过右规使得尾数不再溢出,于是会导致阶码的增大
(2)所以判断两个浮点数运算结果是否溢出,只需判断阶码是否溢出即可(同定点数的判断方法)