由一道习题看如何设计浮点数
2016-09-24 15:12
239 查看
一道浮点数计算的题目,计算了很长时间,最终结果还是因为部分细节出错,导致全盘皆错,因此,有必要认真总结浮点数计算牵涉到的方方面面的数据表示的细节。
这个过程本身相当有趣,因为人脑在处理二进制方面并没有十进制那种直觉。尤其是当在补码下计算,总是得先进行一次数据的反加1才能看出数字的本意,进行一个减法,也需要默念,将减数连通符号位求反加一再和减数相加。甚至不如直接进行十进制数的加减再换算为补码。。
这个过程中需要多次进行这样的计算,仅仅明了计算规则,根本不能解决问题,需要的是细心,以及–实力。
好了,直接看题目,然后再在解析的过程中,一一解释。
已知十进制数X = -5/256, Y = +59/1024,按机器补码浮点运算的规则计算X-Y,结果用二进制表示,浮点数的格式如下:阶符取2位,阶码取3位,数符取2位,尾数取9位。
OK,首先在脑海中建立一种浮点数的格式:阶符+阶码+数符+尾数。
且均用补码表示。
这里题目中给出的小数很nice。
先用自然的语言表示一下,不考虑有多少位数用于存储:
X=−101⋅2−8
Y=+111011⋅2−10
再考虑移位使之满足规格化的形式。
X=−0.101⋅2−5
Y=0.111011⋅2−4
再最终化为补码的形式:
X=11,011;11,011000000 (分号前是阶码的补码表示:-5,分号后面是-0.101的补码表示)
Y=11,100;00,111011000(分号前面是阶码的补码表示:-4,分号后面是0.111011的补码表示)
这里有我比较迷惑的一点,在表示-0.101的时候,化为补码我知道是11.011,但是尾数有9位,在后面要补1还是补0?
如果是补1的话就是:11.011,111,111补化回来就是11.100,000,001原,等同于末尾加了个1,且前面的三位也不是以前的了。因此补1是不行的。
如果补0:11.011,000,000补 化回来是11.101,000,000原
我们知道后面的6个0,求反变成1后,是6个1,再因为加1会变成6个0并且往上进位一个1.
这里是不是因为11.011最低位是1,所以正确,如果是11.010补呢?11.010补对应的原码是11.110原
我们把补码补位到9位:11.010,000,000补,化回来是:11.110,000,000原
模拟这个过程时,突然明白了补0的原因:原码的数据位变补码是求反加1,这个1加在原来数据位的最低位,现在最低位在补的数据位里成了中产阶级,这个1会加到新的数据位长度的位置上,这是不行的,因此这个补贴需要通过链式传递的方式传回来。因此,补位的补码全是0.
解释的原因就是想说,如果一个补码小数被扩大了尾数的表示位数,在低位补0.
Ok,表示结束后,开始对阶:小阶变大阶。
所以是X的阶码往大里变。
X=11,100;11,101,100,000补
Y=11,100;00,111,011,000补
于是再进行尾数求和:[X尾]补−[Y尾]补=[X尾]补+[−Y尾]补
其中[−Y尾]补=[Y尾]补连同符号位求反加一
所以得到:10,110,001,000所以有溢出,需要右规,变成:11,011,000,100.
右归必然使得阶码加1,可以表示成:
11,100+00,001=11,101
于是最终结果是:11,101;11,011,000,100.
也就是:2−3⋅(−0.1001111)2=−0.0771484375
而我们知道,如果真的计算
可见,因为位数的限制,还是有很大的误差的。
这个过程本身相当有趣,因为人脑在处理二进制方面并没有十进制那种直觉。尤其是当在补码下计算,总是得先进行一次数据的反加1才能看出数字的本意,进行一个减法,也需要默念,将减数连通符号位求反加一再和减数相加。甚至不如直接进行十进制数的加减再换算为补码。。
这个过程中需要多次进行这样的计算,仅仅明了计算规则,根本不能解决问题,需要的是细心,以及–实力。
好了,直接看题目,然后再在解析的过程中,一一解释。
已知十进制数X = -5/256, Y = +59/1024,按机器补码浮点运算的规则计算X-Y,结果用二进制表示,浮点数的格式如下:阶符取2位,阶码取3位,数符取2位,尾数取9位。
OK,首先在脑海中建立一种浮点数的格式:阶符+阶码+数符+尾数。
且均用补码表示。
这里题目中给出的小数很nice。
先用自然的语言表示一下,不考虑有多少位数用于存储:
X=−101⋅2−8
Y=+111011⋅2−10
再考虑移位使之满足规格化的形式。
X=−0.101⋅2−5
Y=0.111011⋅2−4
再最终化为补码的形式:
X=11,011;11,011000000 (分号前是阶码的补码表示:-5,分号后面是-0.101的补码表示)
Y=11,100;00,111011000(分号前面是阶码的补码表示:-4,分号后面是0.111011的补码表示)
这里有我比较迷惑的一点,在表示-0.101的时候,化为补码我知道是11.011,但是尾数有9位,在后面要补1还是补0?
如果是补1的话就是:11.011,111,111补化回来就是11.100,000,001原,等同于末尾加了个1,且前面的三位也不是以前的了。因此补1是不行的。
如果补0:11.011,000,000补 化回来是11.101,000,000原
我们知道后面的6个0,求反变成1后,是6个1,再因为加1会变成6个0并且往上进位一个1.
这里是不是因为11.011最低位是1,所以正确,如果是11.010补呢?11.010补对应的原码是11.110原
我们把补码补位到9位:11.010,000,000补,化回来是:11.110,000,000原
模拟这个过程时,突然明白了补0的原因:原码的数据位变补码是求反加1,这个1加在原来数据位的最低位,现在最低位在补的数据位里成了中产阶级,这个1会加到新的数据位长度的位置上,这是不行的,因此这个补贴需要通过链式传递的方式传回来。因此,补位的补码全是0.
解释的原因就是想说,如果一个补码小数被扩大了尾数的表示位数,在低位补0.
Ok,表示结束后,开始对阶:小阶变大阶。
所以是X的阶码往大里变。
X=11,100;11,101,100,000补
Y=11,100;00,111,011,000补
于是再进行尾数求和:[X尾]补−[Y尾]补=[X尾]补+[−Y尾]补
其中[−Y尾]补=[Y尾]补连同符号位求反加一
所以得到:10,110,001,000所以有溢出,需要右规,变成:11,011,000,100.
右归必然使得阶码加1,可以表示成:
11,100+00,001=11,101
于是最终结果是:11,101;11,011,000,100.
也就是:2−3⋅(−0.1001111)2=−0.0771484375
而我们知道,如果真的计算
$X - Y = +0.0380859375$
可见,因为位数的限制,还是有很大的误差的。
相关文章推荐
- 如何在.NET中调试设计时(design-time)控件(下)
- 如何设计出具有GUI特色的“纯”JAVA程序
- 如何在一个系统中设计权限控制机制(2)
- 如何设计心理测试?
- 设计一个图书借阅管理系统需要如何分析
- Think in patten of Java中的一道习题
- 用javascript操作xml-->Web设计中如何使用XML数据源对象(转载)
- 如何设计架构
- 如何设计心理测试?
- 如何设计出具有GUI特色的“纯”JAVA程序
- 如何设计和驱动多任务执行环境(摘抄自inside Vcl)
- BBS 设计思路系列 ---- 如何把有难度,冷门但是关心的人少的问题突出出来??
- 如何在一个系统中设计权限控制机制(1)
- 如何认识设计模式?
- 如何用Tprinter设计BCB操作数据库程序中的报表
- 如何提高网站在Google中的排名——面向搜索引擎的网站设计
- C#中如何使用----按合约设计(Design by Contract)
- 如何调用自行设计的系统调用, --核心开发入门(3)
- 听刘如鸿先生《如何设计具有可扩展性功能的软件架构》感想
- Visio如何反向导出数据库设计文档