一、浮点数介绍
1.1 浮点数格式:
精度 | 位数 | 格式 |
---|---|---|
单精度 float | 4个字节32位 | 符号位1位,阶码8位,尾数23位 |
双精度 double | 8个字节64位 | 符号位1位,阶码11位,尾数52位 |
1.2 浮点的表示方法
浮点数在机器中的形式如下所示,采用这种数据格式的机器称为浮点机
浮点数由阶码j和尾数S两部分组成,阶码是整数,阶符和阶码的位数m合起来反应浮点数的表述范围及小数点的实际位置;尾数是小数,其位数n反映了浮点数的精度,数符表示浮点数的正负。
1.3 浮点数表示范围
设浮点数阶码的数值位取m位,尾数是我数值位取n位,当浮点数为非规格化数时,它在数轴上的表示范围如下所示
当浮点数阶码大于最大阶码时称为上溢,此时机器停止运算,进行中断移出处理,当浮点数阶码小于最小阶码时,称为下溢,此时溢出的数绝对值很小,通常将尾数各位强制置零,按机器零处理,此时机器可以继续运行。
1.4 浮点数的规格化
为了提高浮点数的精度,其尾数必须为规格化数,如果不是规格化数,就需要通过修改阶码并同时左右移位数的方法,使其变成规格化数。将非规格化数转化成规格化数的过程称为规格化。
IEEE 754浮点数的尾数总是规格化的,其范围为1.000…0 × 2e~ 1.111…1 × 2 e ,e为指数。
规格化浮点数的最高位总是1,规格化使尾数的所有位都是有效的,因而尾数精度更高。
如:0.10… × 2 e规 格 化 为 1.10… × 2 e-1
10.1… 2 e 规 格 化 为 1.01… × 2 e+1
尾数规格化充分利用了可用的最大精度。如,一个8位非规格话的尾数0.0000101只有4位有效位,而规格化后的8位尾数1.0100011则有8位有效位。
二、浮点数转换二进制
不论是float还是double在存储方式上都是遵从IEEE的规范(IEEE floating point standard)的,float遵从的是IEEE R32.24 ,而double 遵从的是R64.53。IEEE 标准如下:
举例:123.125(10) 分开 “整数” 和 “小数” 两部分来转二进制
123(10)转二进制是:0111 1011(2)
0.125(10)转二进制是:011(2)
0.125 * 2 = 0.25------0
0.25 * 2 = 0.5----------0
0.5 * 2 = 1.0-------------1
(具体转化规则不做详细解释)
根据上面两段生成的是:111 1011.001(2)
用科学记数法表示:1.111011001 * 2^6
不要 1. 剩下的111011001就是尾数(M),
为什么不要1. 呢?是因为1. 是肯定会有的,所以直接被省略了,取数时候会自动加上1. 来计算
指数(E)=6+127 = 133(10) = 1000 0101(2)
6就是1.111011001 * 2^6 的 6
127由来:因为float的指数(E)是8位,所以根据2^(8-1) - 1 = 127
为什么要指数(E)是6+127呢?
因为指数可能有负数即6也有可能是-6,所以要加上一个数,方便计算,而加上的这个数是根据float和double约定好的固定值。( double的指数(E)是11位,所以如果是double,就要将127改为2^(11-1) - 1 = 1023 )
符号(S):正数 = 0,负数 = 1
所以123.125 = 0 10000101 1110110010000000000000
三、浮点数运算步骤
3.1 浮点数的加减运算的五个步骤:对阶、尾数运算、规格化、舍入(要求使用对偶舍入)(0舍1入)、溢出判断。
-
类型提升和对齐:如果两个参与运算的浮点数类型不同,例如一个是
float
类型,另一个是double
类型,那么float
类型的数值通常会首先被提升(类型转换)为double
类型,这个过程称为类型提升。提升之后的两个数的指数(Exponent)部分需要对齐,即保证它们有相同的指数。 -
对阶:要实现加减运算,比较小的数的尾数(Mantissa)会根据指数的差异进行右移,直到两个数的阶码相同。在右移的过程中,可能会有精度损失。
-
尾数运算:当指数对齐后,尾数进行加减运算。对于加法,相同位上的尾数值相加;对于减法,相减。
-
规格化:加减运算后的结果可能不是规格化的浮点数,所以接下来需要进行规格化处理。这意味着尾数可能需要左移或右移,同时调整指数值,确保尾数的最高有效位(通常)为1。
-
舍入处理:浮点数的位数是有限的,所以在规格化的过程中,尾数可能需要被截断,这就需要根据选定的舍入模式(如向最近偶数舍入、向下舍入等)来处理这些多余的位。
-
溢出判断:计算结果可能超出浮点数的表示范围,这可能导致溢出(overflow)或者下溢(underflow)。根据IEEE 754标准,溢出可能会导致得到无穷大表示,而下溢可能导致得到最接近零的数(丢失精度),或者产生特殊的非规格化数(subnormal numbers)。
3.2 计算实例
由于IEEE标准下的浮点操作数已被表示为规格化形式,计算机在进行浮点加法时,为了对齐指数,计算机必须执行下面步骤:
第一步,找出指数较小的数
第二部,使两个数的指数相同
第三步,尾数相加
第四步,如果有必要,将结果规格化
以一个简单的8位尾数和一个未对齐的指数为例说明浮点运算,A = 1.0101001 × 24 , B=1.1001100×23,计算A+B
注意:
(1)因为IEEE754标准的32位单精度浮点数的指数与尾数位于位于同一个字中,所以在加法过程开始之前必须将它们分离开。
(2)如果两个指数的差大于p+1,p为尾数的位数,这里p=23,较小的数由于太小而无法影响较大的数,结果实际就等于较大的数。
(3)结果规格化时检查指数范围,以分别检测指数下溢或上溢。指数下溢会导致结果为0,而指数上溢出会造成错误。
3.3 舍入机制
浮点运算可能引起尾数位数的相加,需要保持尾数位数不变的方法。最简单的技术叫作截断。
比如将0.1101101截断为4位尾数的结果为0.1101。截断会产生诱导误差(即误差是由施加在数上的操作计算所引起的),诱导误差是偏差的,因为截断后的数总比截断数小。
舍入是一种更好的减少数的尾数的技术。如果舍弃的位的值大于剩余数的最低位的一半,将剩余数的最低位+1。
要找到中间值,先确定要保留的有效数字,找到要保留的有效数字最低位的下一位。如果这位是进制的一半,而且之后的位数都为 0,则这个值就是中间值。
舍入机制:
(1)最简单的舍入机制是截断或向0舍入。
(2)向最近的数舍入:选择距离该数最近的那个浮点数作为结果。
(3)向正或负无穷大舍入:选择正或负无穷大方向上最近的有效浮点数作为结果。
(4)向偶数舍入:当要舍入的数位于两个连续浮点数的正中时,IEEE舍入机制选择最低位为0的点(即向偶数舍入)
舍入到最近的偶数例子:
十进制的 1.2500,要保留到小数点后一位,下一位是 5,是进制的一半,后面位数都为 0,所以这个值就是中间值
二进制的 10.0110,要保留到小数点后两位,下一位是 1,是进制的一半,后面位数都为 0,所以这个值就是中间值
知道了舍入规则之后(舍弃的位的值大于剩余数的最低位的一半),
看几个具体的例子,以二进制为例,有效位数保留到小数点后两位(保留两位数的话,0.xx1是余数的最低位的一半)。
10.00_011,中间值为 10.00100,小于中间值,向下舍入为 10.00
10.00_110,中间值为 10.00100,大于中间值,向上舍入为 10.01
10.11_100,中间值为 10.11100,等于中间值,要保留的最低有效位 1 为奇数,向上舍入为 11.00
10.10_100,中间值为 10.10100,等于中间值,要保留的最低有效位 0 为偶数,向下舍入为 10.10