浮点数和机器精度

本文探讨了浮点数表示及其带来的精度问题,通过具体实例展示了二进制表示下的误差来源,解释了double和float的精度差异,并讨论了特殊值如NaN和INF的含义。

在优化代码的过程中再次遇到数据瓶颈——精度问题,不得不再温习一下这个自以为很了解的主题:浮点数和精度。

为什么一个简单的整数,在计算机内的值并不一致?例如,实际数值558783388,在float下是558783360,而

log2( 558783388)

ans =

   29.0577
log2( 558783360)

ans =

   29.0577
在double下是5.587833745970526e+08,因为double精度比float高,所以更加逼近实际数值

误差


这一切就是因为二进制,用二进制表示一个数(十进制数),是有误差的。再举一个例子:

double a=0.2;
在内存中,我们可以看到a对应的存储区数据是:

9A 99 99 99 99 99 C9 3F
这是小端(little endian)存储方式,换成高位在前:

3F C9 99 99 99 99 99 9A

double在内存中的形式如下(详细请看IEEE 754浮点运算标准):

63(1 bits) 62~52(11 bits)  51~0(52 bits)
符号位       指数位(阶码)     尾数
             (-1022~1023)

可见符号位为0,指数位是0x3FC,即1020,减去2^10-1,即1023,得指数为-3;尾数是999999999999A。所以完整的数字就是16进制的1.999999999999A乘上2^-3,得

a=0.2000 0000 0000 0000 1110 2230 2462 5157
已经可以看到用double表示0.2时存在的误差。这个例子说明在用有限字长的二进制浮点数表示任意实数a可能引入误差。设实数a的指数为e,尾数位数为n,显然:误差<(1/2^n)*2^e


精度

可以把机器精度定义为满足条件:

float(1+ε)>1

的最小浮点数ε。显然double的机器精度是1/2^52。float的机器精度是1/2^23。上面的例子就是,十进制数的0.2后面第17位开始有误差,即10^-16:

10^-16

ans =

   1.0000e-16
 2^-52

ans =

   2.2204e-16
double而今不足以确定其精度,其最小只能到:

10^-15

ans =

   1.0000e-15
上面说的是小数位,更科学的说法是有效数字。因为小数点前默认有个1,所以float的有效数字是24bit,对应8位十进制有效数字; double的有效数字是53bit,对应16位十进制有效数字。也就是说,如果一个实数的有效数字超过8位,用单精度浮点数来表示的话,就会产生误差!同样,如果一个实数的有效数字超过16位,用双精度浮点数来表示,也会产生误差!


NaN和INF

在matlab中经常遇到,计算后的矩阵中存在这两个符号。它们属于特殊的浮点数。一旦阶码为0或全1,就会出现特殊浮点数。


# 当指数全0的情况下,如果尾数为0,根据符号位不同可以分为+0和-0;如果尾数为非0,即尾数部分不假设前面存在小数点前的1。或者说这些数太接近0了,因为指数已经不能再小。例如一个double变量在内存中的表示(十六进制):

00 00 00 00 00 00 00 01
阶码为0,指数直接等于-1022,尾数为1/2^52,故结果为:

4.9406564584124654e-324

# 当指数全1的情况下,如果尾数为0,表示无穷,根据符号位确定是+INF、-INF;如果尾数非0,表示NaN非数值


归纳如下表:浮点数的特殊值(double)

符号位    阶码    尾数    数值
0         0        0      +0
1         0        0      -0
0         2047     0      +∞
1         2047     0      -∞
0         2047     非0    NaN

总结

float和int都是32bit,但float的尾数只用了23bit。int的精度高于float,float的表示范围大于int。float牺牲精度换取了更大的表示范围。 double的尾数是52bit,高于32bit的int,所以用dobule表示int不会有精度损失。 double是科学计算的常用类型,了解double的内在和限制,有助于我们更好地使用它。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值