打字猴:1.701005347e+09
1701005347 我和数学有约:趣味数学及算法解析 [:1701004185]
1701005348 我和数学有约:趣味数学及算法解析 3.1 0.1-0.3+0.2等于0吗
1701005349
1701005350 0.1-0.3+0.2等于0,对于我们而言,我们都会异口同声的说出等于0,然而对于计算机而言,0.1-0.3+0.2等于0吗?
1701005351
1701005352 【问题】0.1-0.3+0.2等于0吗?
1701005353
1701005354 【分析】
1701005355
1701005356 计算机认账吗?0.1-0.3+0.2等于0吗?现在利用MATLAB进行一组运算:
1701005357
1701005358     clc,clear,close all  %清屏和清除工作区变量    warning off       %消除警告    0.1+0.2-0.3       %计算    0.1-0.3+0.2
1701005359
1701005360 运行程序输出结果如下:
1701005361
1701005362     ans =       5.5511e-17    ans =       2.7756e-17
1701005363
1701005364 我们从MATLAB输出结果可看到,上式的结果不为0呢?0.1+0.2-0.3不等于0,0.1-0.3+0.2不等于0,更加神奇的是0.1+0.2-0.3不等于0.1-0.3+0.2,这是为什么?为什么不同的运算顺序结果不一样呢?下面我们详细解释这个原因。
1701005365
1701005366 在此,读者需要先了解《1985年IEEE发布了二进制浮点运算标准754-1985》。
1701005367
1701005368 根据IEEE浮点数运算标准,我编写了两个简单的程序,用于IEEE数值和double数值之间的转换。
1701005369
1701005370 IEEE数值转换为double数值,函数程序文件如下:
1701005371
1701005372     function [x_double,s,c,f]=ieee2double(x_ieee)    %将IEEE编码转换为双精度数据    %x_double=(-1)^s*2^(c-1023) * (1+f),双精度数据    %x_ieee,IEEE编码    %s,符号位,长度1    %c,指数位,长度11    %f,尾数位,长度52    %    s=bin2dec(x_ieee(1));         %二进制转十进制    c=bin2dec(x_ieee(2:12));      %二进制转十进制    m=bin2dec(x_ieee(13:64)’);    %二进制转十进制    %为了保证精度,使用符号运算    f=sym(‘1/2’).^(1:52) *m;    x_double=(-1)^s*2^(c-1023) * (1+f);
1701005373
1701005374 double数值转换为IEEE数值,函数程序文件如下:
1701005375
1701005376     function [x_ieee,s,c,f]=double2ieee(x_double)    %将双精度数据转换为IEEE编码    %x_double=(-1)^s*2^(c-1023) * (1+f),双精度数据    %x_ieee,IEEE编码    %s,符号位,长度1    %c,指数位,长度11    %f,尾数位,长度52        if x_double>0        s=‘0’;    else        s=‘1’;    end    n=floor(log2(x_double));      c=dec2bin(n+1023,11);                            %十进制转二进制    f=dec2bin(round((x_double/2^n-1) *2^52),52);     %十进制转二进制    x_ieee=[s,c,f];
1701005377
1701005378 利用上面的double2ieee()函数尝试得到0.1的IEEE编码,程序如下:
1701005379
1701005380     clc,clear,close all             %清屏和清除变量    warning off                     %消除警告    x_double=0.1;                       x_ieee_01=double2ieee(x_double) %将双精度数据转换为IEEE编码
1701005381
1701005382 运行程序输出结果如下:
1701005383
1701005384     x_ieee_01 =    0011111110111001100110011001100110011001100110011001100110011010
1701005385
1701005386 也就是说0.1的IEEE编码就是由一系列0和1组成,其实这串二进制代表的真实数据略大于0.1,也就是说:
1701005387
1701005388     ieee(0011111110111001100110011001100110011001100110011001100110011001)    < double(0.1) <    ieee(0011111110111001100110011001100110011001100110011001100110011010)
1701005389
1701005390 我们都知道计算机是二进制存储数据的,由于0.1没有精确的IEEE编码,根据就近一致原则,0.1采用的IEEE编码就采用最近的第二个编码。
1701005391
1701005392 【问题】0.1两个编码到底代表什么数据呢?
1701005393
1701005394 【分析】
1701005395
1701005396 下面使用ieee2double()函数来测试如下:
[ 上一页 ]  [ :1.701005347e+09 ]  [ 下一页 ]