matlab双精度浮点数编码及区间覆盖(原创)
(posted on may 31,2011)
(Firstly justified on jun 6,2011)
十进制数常用科学计数法表示,如11=1.1*10^1, 111=1.11*10*2. 同样地,二进制数也有科学计数法表示,如64, 1000000=1.000000*2^6; 127, 1111111=1.111111*2^6; 128, 10000000=1.0000000*2^7. 由于表示成科学计数法时第一位数总是1, 所以计算机以科学计数法存储二进制数时默认把第一位数上的1省去,只存储小数点后面的部分。
matlab默认以64位双精度浮点格式存储数据于工作空间(workspace),第0位到第51位为小数部分,第52位到62位为指数部分,第63位为符号(正或负)部分。从排列组合的角度考虑,共有64位,每个位有0和1两种状态,因此64位最多能够表示的状态数为2^64个,即最多能够表示 2^64个不同的数值。把这些数值按照从小到大的顺序排列,相邻的两个数之间就会出现空隙。如果一个数恰好落入空隙中,matlab怎么处理这个数呢?下 面以具体实例来说明。
64,127和128这三个数的二进制表示分别为:1000000,1111111,10000000. 其在计算机中的存储示意图如下:
64 的指数部分为6,系数部分为0000000……0,加上缺省的1,成为1.0000000……0,根据二进制数的科学计数法,小数点依据系数值向右偏移6 个单位,复原出64 的二进制码1000000.0……0. 由于小数点需要向右偏移,这样在存储上最右边一位的量级就是2^-46,这正是matlab函数eps给出的值,即计算机能存储的比64大的第一个值是 64+2^-46. 并且,区间 [64, 128) 之间的所有数由于小数点偏移的都是6位,所以这些数的eps都是2^-46. 根据这样的分析,虽然128只比127大1,但128的二进制码需要偏移7为,导致最后一位的量级为2^-45,所以eps(128)=2^-45. 可见一个十进制数的eps值是根据这个数的整数部分用二进制科学计数法表示时的小数点偏移量来定的,且随着偏移量的增大,eps也增大。
整数可以用二进制码精确表示,当1位符号部分和11位指数部分确定之后,系数的52位最多能够编码出2^52个数。图中,当指数部分确定是6,就要用
2^52个数表示区间 [64,128)
中的数。这样,每个计算机能够编码的数都要覆盖一个小区间,计算机认为这个区间内的任何数都与这个数相等,才能用有限的数覆盖一个连续区间。在
matlab中试验发现,一个数覆盖的区间长度就是这个数的eps值,并且这个数处于这个区间的中心,但是区间端点是属于本区间还是属于紧挨的区间不一
定,以[64, 128)上的小区间为例,区间是开区间与闭区间间隔连在一起的。
(64+0.5*eps(64), 64+1.5*eps(64))[64+1.5*eps(64), 64+2.5*eps(64)](64+2.5*eps(64),64+3.5*eps(65))[64+3.5*eps(64),64+4.5*eps(64)]……
还有一类特殊的整数,像64和128,刚好处于指数位变化的地方,试验发现,64和128覆盖的区间分别是 [64-0.5*eps(63), 64+0.5*eps(64)],
[128-0.5*eps(64), 128+0.5*eps(128)]. 即这类区间是闭区间,但是这个数不在这个区间的中心,数的左边是上个eps值的一半,数的右边是本eps值的一半,并且左边的区间长度是右边区间长度的一半。
根据上面的理论,可以对“大数吃掉小数”的问题提供一个依据。当一个数加或减的数小于这个数的eps值的一半时,计算机是忽略的。那么一个数是这个数的 eps值的多少倍呢?64=2^6, eps(64)=2^-46; 64+(2^52-1)*eps(64)~128, eps(64+(2^52-1)*eps(64))=eps(64).所以,一个数除以这个数的eps得到的值应该属于区间 [2^52, 2^53).