浮点数编码的分析
通过一个实例来分析浮点数编码中的一些细节。
假设一个基于IEEE 754标准的5位浮点数,包含1位符号位、2位阶码位和2位尾数位。
非规格数:0.fx2(1-Bias);
规格数:1.fx2(e-Bias);
其中,Bias=2(2-1)-1=1;
下面真值表只列出正数(符号位s=0)的情况,负数的真值类似。
s(1) | e(2) | f(2) | 实际值 | |
非规格数 | 0 | 00 | 00 | 0.00x2(1-1)=0/4 |
0 | 00 | 01 | 0.01x2(1-1)=1/4 | |
0 | 00 | 10 | 0.10x2(1-1)=2/4 | |
0 | 00 | 11 | 0.11x2(1-1)=3/4 | |
规格数 | 0 | 01 | 00 | 1.00x2(1-1)=4/4 |
0 | 01 | 01 | 1.01x2(1-1)=5/4 | |
0 | 01 | 10 | 1.10x2(1-1)=6/4 | |
0 | 01 | 11 | 1.11x2(1-1)=7/4 | |
0 | 10 | 00 | 1.00x2(2-1)=8/4 | |
0 | 10 | 01 | 1.01x2(2-1)=10/4 | |
0 | 10 | 10 | 1.10(2-1)=12/4 | |
0 | 10 | 11 | 1.11x2(2-1)=14/4 | |
特殊数 | 0 | 11 | 00 | 正无穷 |
0 | 11 | 01 | NaN | |
0 | 11 | 10 | NaN | |
0 | 11 | 11 | NaN |
从上表可以看出一些规律:
- 为什么非规格数的指数采用(1-Bias)而不是与规格数一致的(e-Bias)?从非规格数0.11x2(1-1)=3/4过渡到规格数1.00x2(1-1)=4/4,步进为1/4,与相邻步进一致;若非规格采取和规格数一样的阶数偏移方式,即0.fx2(e-Bias),则从非规格数过渡到规格数的过渡为 0.11x2(0-1)=3/8->4/4,出现了不连续,为了达到平滑过渡,于是令非规格数的算式为0.fx2(1-Bias)。
- 为了表示0附近的小数,需要采用规格化数;
- 浮点数的表示数值是有限且离散的,对于上述表格之外的数,只能选取最接近该数的取值来表示(位于正中间的数,目前实验来看,采取向下取值,可能是为了使相对误差最小化);
- 随着数值的增大,阶码随之增大,即增加一位尾数所带来的增值也随之增大,即步进越来越大,也就是这一副图的由来。
浮点数的精度
对于浮点数的精度问题,官方说float约为7位十进制,double约为16位十进制,这里的的精度有说是有效数字,也有说小数点后面的数,但例如1.14454686641693115234375,其有效数和小数点后位数远超过上述范围,但是在计算机内部却能够准确表示,如下图所示。所以这里精度的意思应该不是这个。目前看到最准确的说法是这个精度表示的是相对误差的大小,即
∣
误
差
真
实
值
∣
\left | \frac{误差}{真实值} \right |
∣∣真实值误差∣∣。
例如下图,对于输入数值12345.6789,其相对误差为
=
∣
−
0.0001890625
12345.6789
∣
≃
1.5314
×
1
0
−
8
=\left | \frac{-0.0001890625}{12345.6789} \right |\simeq 1.5314\times10^{-8}
=∣∣12345.6789−0.0001890625∣∣≃1.5314×10−8。
推导如下,任意选取一个浮点数,理想情况下,选取的数值刚好位于离散点上,此时相对误差为0;但若位于两个离散点之间时,最坏情况位于两者之间,且向下舍入,此时相对误差最大,为10-8这个数量级,但这和官方的7位有效数字有出入,但相对误差确实是一个可以用来量化浮点数表示精度的参数。
综上,计算机中的有限精度数值与自然数中的无限精度之间必然存在转换误差,而这个误差不会超过实际值的10-8倍这个数量级。由此可见计算机的浮点数的存储精度已经相当准确。(浮点数运算时还会产生额外误差,详情见计算机中的小数(下)-浮点数的运算)。