1701005340
我和数学有约:趣味数学及算法解析 第3章 数字之美
1701005341
1701005342
数学之美,无异于数字之美。别小看0~9这10个数字,它构成了世间万物,一切都归结为0~9的组合,从而编织成神奇的大自然,数字黑洞、幻方、回文数和142857等组合数之美,都只是数字组合中的一部分,数字之美,任你玩转,如果你足够具有挑战精神,你会得到很惊奇的发现。
1701005343
1701005344
1701005345
1701005346
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)
[
上一页 ]
[ :1.701005339e+09 ]
[
下一页 ]