这几天看c primer plus上写的,对于浮点数的溢出的**含义**可以理解,但是具体在**二进制代码**中的体现摸不清楚。	通常,这个操作会减小指数部分,但是假设的情况中,指数是最小值了,所以计算机只好把尾数...
按:计算机组成课程第四周作业算法证明 图表 1浮点数的表示浮点数的表示如上图所示,我们要做的是将按如上方式存储的两个浮点数相乘,将其结果用如上的方式表示。符号位只是两者的异或,指数位基本上是两指数的相加...
按:计算机组成课程第四周作业
算法证明
图表 1 浮点数的表示
浮点数的表示如上图所示,我们要做的是将按如上方式存储的两个浮点数相乘,将其结果用如上的方式表示。
符号位只是两者的异或,指数位基本上是两指数的相加,而尾数位就需要在正常的乘法之余考虑到移位(和随之而来的指数为的溢出)和进位的情况。
下面就来讨论一下尾数的运算:
在尾数前补上1,进行无符号数乘法。小数点仅作为算法分析时的记号,实际上不参加运算。用64位的long long类型的数来存储运算结果。
图表 2 尾数相乘(用“画图”程序画的)
如上图所示,后46个数字是结果的小数点后的数据,小数点的的问号处可能只有1,可能是1X(10或11,在算法中没有太大区别)。若问号处只有1,说明已经规格化完成;若是1X,需要将整个数右移一位,质数加一,从而使问号处只有1。
规格化后要进行round操作,如下图所示。如果第23位是0,这一位之前的23位就是所需要的尾数。如果第23位是1,截取这位之前的数,加一(类似于四舍五入)。判断结果是否仍规格化。若没有规格化,从规格化开始继续做,直到找到规格化后的23位尾数。
图表 3 有效数处理(用“画图”程序画的)
程序框图
主要流程如下图所示。在代码注释中的Step1到step5即分别对应流程图中的1至5部分。有所不同的是,因为后面只会增加exponent而不会减少,所以我的程序在step1就判断是否overflow,在step3也判断是否overflow就行了,规格化完成后再判断underflow。
图表 4 浮点乘法程序框图
使用方法
输入两个数,程序用自带的scanf将其作为单精度浮点数读入。通过一系列的无符号数的计算,得到用单精度浮点数表示的结果,将其输出(为了更详细地看到整个数,输出的数小数点后有20位)。如果overflow或underflow,输出的是相应的提示。为了验证计算是否正确,在输出的数据后面有个括号,里面放了是直接让机器进行的单精度浮点数的乘法的结果。
特殊处理
特殊输入数据
有些输入的数据是在太大或太小,以至于数据本身就已经overflow或underflow,从而根本无法存贮到单精度浮点数中,不是合法的单精度浮点数。对于这样的数,我们不应该对其提供任何服务,不然只会闹出笑话。
对于零要特殊处理,因为0在浮点数中的表示并不是按照一般的规范来的。
溢出
这里的溢出指的是乘数和被乘数本身是合法的单精度浮点数,但相乘后造成了溢出。
因为后面只会增加exponent而不会减少,所以与上面的流程图不同,我的程序在step1就判断是否overflow,在step3也判断是否overflow就行了,规格化完成后再判断underflow。
数位扩展
整个程序都是按照单精度的浮点数来写的,数位扩展可能有点麻烦。如果要扩展为双精度的,需要更改代码中的大量参数。鉴于浮点数一般也就只有单精度和双精度两种,我觉得不是太必要提高做成可扩展的。
实例分析
图表 5 大数的乘法
图表 6 overflow
图表 7 underflow(本程序判为underflow,而C语言自己的浮点数乘法计算结果为0.000000)
图表 8 对0的乘法
图表 9 很大的与很小的正数相乘
图表 10 观察精确度
图表 11 对负数乘法的测试
图表 12 对于无法用浮点数表示的输入数据
图表 13 对于过小的数据
结果分析
我们对过于大的数据和过于小的数据,以及精度太大的数据都做了试验。从上述结果可以看到,这个程序的结果与C程序自带的浮点数乘法结果基本吻合。说明这个程序还是比较可靠的。
通过对精度的测试,我们发现浮点数虽然能表示较大较小的数据,但有效数字还是有限的。如-100与0.6相乘的结果,整数部分60是对的,小数点五位后就出现了偏差。一连串8与1相乘,结果的头部只有7个8。可以大致地认为浮点数的表示与计算的十进制有效数位是7位。
可以更进一步的工作
l 程序中对于无符号整数的加法、乘法,对于exponent的有符号整数运算都是直接使用的,其实可以调用之前写的相关程序,做成更加本质的浮点数乘法。