Matlab中有一个函数名为eps
- 格式:doc
- 大小:23.00 KB
- 文档页数:2
Matlab中有一个函数名为eps,文档中对这个函数的说明是:Floating-point relative accuracy.它的具体功能是什么呢?
数字计算机所处理和存储的数据,都是量化过的数据,因此不能拥有任意的精度。对于以整数形式保存的数据,数与数的最小间隔为1,不能再小。而float类型同样,数与数之间存在一个最小间隔,但这个间隔并不是常数,而是随着数字的大小而改变的。举一个简单的例子,我们用科学计数法来表示数值,规定尾数部分只能保留一位小数。那么1.0×102,与它相邻的数字有1.1×102,处在这两个数中间的数值无法精确表示,因为只能保留一位小数。这两个相邻的数字的间隔是多少呢?1.1×102-1.0×102=10。也就是说,在这种计数方式的制约下,我们所能表示的数都是以十为间隔。但是这并不是一成不变的,对于1.0×103而言,与它相邻的数有1.1×103,处于这两个数中间的数值无法精确表示。它们的间隔是1.1×103-1.0×103=100。此时我们能够用这种计数方式表示的数以100为间隔。可见数值越大,精度越低。
对于使用二进制存储浮点数的754标准而言,relative accuracy与上面所描述的十进制的情况类似。754标准所规定的存储方式与科学计数法很相似,但是有一些细节问题需要注意,如最高位的1不存储,指数部分的偏移量,inf,NaN的存储方式等等。
想要完全了解relative accuracy,一个简单的方法是自己实现一个eps函数,并与Matlab自备的eps进行比较。我试着写了一个,值得注意的是我所使用的版本是Matlab 7.7,代码中使用了typecast函数,该函数在7.x的早期版本中不存在。还有一点就是此代码用于常见的Intel处理器+Windows操作系统,如果在其它架构上编写类似代码,好像要考虑大小端模式的问题。
my_eps.m:
function r=my_eps(d)
d=abs(d);
if ((d==inf) || isnan(d))
r=NaN;
return;
end
bytes=typecast(d,'uint8');
e=typecast(bytes(end-1:end),'uint16');
switch class(d)
case'double',
bs=4;
subnum=52;
zeronum=6;
le_rmin=2^(-1074);
case'single',
bs=7;
subnum=23;
zeronum=2;
le_rmin=2^(-149);
otherwise,
error('Only Single & Double classes are supported!');
end
if (d<=realmin(class(d)))
r=le_rmin;
return;
end
e=bitshift(e,-bs)-subnum;
e=bitshift(e,bs);
e=typecast(e,'uint8');
r=typecast([zeros(1,zeronum,'uint8') e],class(d));
这段代码很简单,为了说明其原理,还是以十进制的科学计数法为例(假设只能保留一位小数):
对于一个数,想要知道与它与其最相邻的数之间的间隔,只要保持该数的指数部分不变,尾数部分最右边的那一位为1,其余为0即可,例如,我想知道1.2×108与相邻数之间的间隔,保持指数部分不变,尾数只有最右边一位为1,其余为0,得到:0.1×108。但事情并没有结束,得到的这个数的形式并不符合规范,我们必须保证尾数部分个位为1才行,所以要将尾数左移一位,左移的同时,要减少指数,移一位,指数就要减1,最终符合规范的数值是1.0×107。
原理是这样,但技术上的问题比较烦人。先看一下double类型的存储格式:
SEEE EEEE EEEE MMMM MMMM MMMM MMMM MMMM MMMM MMMM MMMM MMMM MMMM MMMM MMMM MMMM
S代表符号位,E代表指数位,M代表尾数。为了取得指数的数值,须将最左边的两个字节左移4位:
0000 0EEE EEEE EEEE
然后将尾数部分的最右边一位置1,其余为0。为了符合规范,须将这个唯一的1移动到尾数的各位上,这一操作一共要左移52位,相应的,指数部分要减52。my_eps函数的最后几行就是完成这样的操作。
float类型的操作类似,只是存储格式有些许差别,为:
SEEE EEEE EMMM MMMM MMMM MMMM MMMM MMMM
最后,还有一点值得注意,即判断一个变量是否是NaN,不要写成d==NaN,Matlab 规定NaN≠NaN。正确的做法是使用isnan函数进行判断。